冰楓論壇

標題: PIC32MX250F128B [打印本頁]

作者: 洪嵐峰    時間: 2023-4-24 19:51
標題: PIC32MX250F128B
製作數控可調直流穩壓電源,需要以下零件:

PIC32MX250F128B 微控制器
16x2 字元液晶顯示器
旋轉編碼器
電位器
MOSFET 集成電路
散熱器
連接線、電阻、電容等基本元件

程式碼可以根據需求進行編寫
實現電源輸出電壓和電流的控制:

#include <xc.h>
#include <plib.h>

// 設定定時器的計數值,用於 PWM 輸出控制
#define TMR2_PRESCALER  64
#define TMR2_PERIOD     500

// 定義腳位
#define LCD_RS          LATEbits.LATE0
#define LCD_RW          LATEbits.LATE1
#define LCD_EN          LATEbits.LATE2
#define LCD_D4          LATBbits.LATB8
#define LCD_D5          LATBbits.LATB9
#define LCD_D6          LATBbits.LATB10
#define LCD_D7          LATBbits.LATB11
#define ENCODER_A       PORTBbits.RB0
#define ENCODER_B       PORTBbits.RB1
#define POT             ADC1BUF0

// 變量定義
unsigned int voltage_setting = 0; // 電壓設置值
unsigned int current_setting = 0; // 電流設置值
unsigned int voltage_adc_val = 0; // 電壓 ADC 值
unsigned int current_adc_val = 0; // 電流 ADC 值
unsigned int voltage_dac_val = 0; // 電壓 DAC 值
unsigned int current_dac_val = 0; // 電流 DAC 值
unsigned char encoder_val = 0; // 編碼器值
unsigned char encoder_old_val = 0; // 編碼器舊值
unsigned char encoder_state = 0; // 編碼器狀態

// 函數原型
void init_system(void);
void init_lcd(void);
void init_adc(void);
void init_dac(void);
void init_pwm(void);
void display_voltage(unsigned int value);
void display_current(unsigned int value);

// 主函數
int main(void)
{
    // 初始化系統
    init_system();

    // 顯示歡迎信息
    lcd_clear();
    lcd_puts("DC Power Supply");
    lcd_gotoxy(0, 1);
    lcd_puts("by Your Name");

    // 主循環
    while (1)
    {
        // 讀取編碼器值
        encoder_val = 0;
        if (ENCODER_A == 1) encoder_val |= 0x01;

    if (ENCODER_B == 1) encoder_val |= 0x02;

    // 根據編碼器狀態調整設置值
    if (encoder_val != encoder_old_val)
    {
        encoder_state = (encoder_state << 2) | encoder_val;
        if ((encoder_state & 0x0F) == 0x02) voltage_setting++; // 編碼器順時針旋轉,增加電壓設置值
        if ((encoder_state & 0x0F) == 0x01) voltage_setting--; // 編碼器逆時針旋轉,減少電壓設置值
        if ((encoder_state & 0x0F) == 0x08) current_setting++; // 編碼器順時針旋轉,增加電流設置值
        if ((encoder_state & 0x0F) == 0x04) current_setting--; // 編碼器逆時針旋轉,減少電流設置值
        encoder_old_val = encoder_val;
    }

    // 顯示設置值
    display_voltage(voltage_setting);
    display_current(current_setting);

    // 讀取 ADC 值
    voltage_adc_val = ADC1BUF1;
    current_adc_val = ADC1BUF2;

    // 轉換 ADC 值到 DAC 值
    voltage_dac_val = voltage_adc_val / 16;
    current_dac_val = current_adc_val / 16;

    // 設置 DAC 輸出
    DacChnSet(1, voltage_dac_val);
    DacChnSet(2, current_dac_val);

    // 設置 PWM 輸出
    SetDCOC2PWM(voltage_setting * TMR2_PERIOD / 1024);
    SetDCOC3PWM(current_setting * TMR2_PERIOD / 1024);

    // 稍作延遲
    DelayMs(10);
}

return 0;
}

// 初始化系統
void init_system(void)
{
// 設置 CPU 頻率為 80 MHz
SYSTEMConfigPerformance(80000000);

// 設置 I/O 口
AD1PCFG = 0xFFFF;
TRISBbits.TRISB8 = 0; // LCD D4
TRISBbits.TRISB9 = 0; // LCD D5
TRISBbits.TRISB10 = 0; // LCD D6
TRISBbits.TRISB11 = 0; // LCD D7
TRISEbits.TRISE0 = 0; // LCD RS
TRISEbits.TRISE1 = 0; // LCD RW
TRISEbits.TRISE2 = 0; // LCD EN
TRISBbits.TRISB0 = 1; // Encoder A
TRISBbits.TRISB1 = 1; // Encoder B

// 初始化 LCD
init_lcd();

// 初始化 ADC 和 DAC
init_adc();
init_dac();

// 初始化 PWM
init_pwm();
}

// 初始化 LCD
void init_lcd(void)
{
LcdInit();
LcdClear();
}

// 初始化 ADC
void init_adc(void)
{
AD

// 設置 ADC 輸入口和模式
AD1CON1 = 0x00E0; // 自動轉換模式,TAD = 3 TCY
AD1CON2 = 0x0800; // AVDD/AVSS 參考電壓,輸入 A 和 B 交替轉換
AD1CON3 = 0x1F02; // 時間 TAD = 3 TCY,自動掃描 2 個輸入口,每個輸入口掃描 2 次
AD1CSSL = 0x0000; // 不使用掃描模式

// 啟動 ADC
AD1CON1bits.ADON = 1;

初始化 DAC

// 設置 DAC 輸出口和模式
DacRegs.DAC1CON = 0x0790; // 工作模式為雙通道、單端輸出、電壓參考為 AVDD/AVSS、輸出增益為 1x
DacRegs.DAC2CON = 0x0790; // 工作模式為雙通道、單端輸出、電壓參考為 AVDD/AVSS、輸出增益為 1x

初始化 PWM

// 設置 TMR2 和 OC2/OC3 輸出口和模式
T2CON = 0x8030; // TMR2 周期為 1 ms,分頻係數為 1:256,啟用 TMR2
PR2 = TMR2_PERIOD - 1; // 設置 TMR2 周期為 1 ms
OC2CON = 0x0006; // 輸出模式為 PWM,Duty Cycle = 0
OC3CON = 0x0006; // 輸出模式為 PWM,Duty Cycle = 0
SetDCOC2PWM(0); // 設置 OC2 初始值為 0
SetDCOC3PWM(0); // 設置 OC3 初始值為 0
}

// 顯示電壓設置值
void display_voltage(int voltage_setting)
{
char buf[17];
sprintf(buf, "Voltage: %4d mV", voltage_setting * 100);
LcdSetCursor(0, 0);
LcdWriteString(buf);
}

// 顯示電流設置值
void display_current(int current_setting)
{
char buf[17];
sprintf(buf, "Current: %4d mA", current_setting * 10);
LcdSetCursor(0, 1);
LcdWriteString(buf);
}

// 延遲指定時間(毫秒)
void DelayMs(int ms)
{
int i;
for (i = 0; i < ms; i++)
{
int j;
for (j = 0; j < 8000; j++);
}
}

// 主程序
int main()
{
// 初始化 LCD
LcdInit();

// 顯示歡迎信息
LcdClear();
LcdWriteString("DC Power Supply");
LcdSetCursor(0, 1);
LcdWriteString("by ChatGPT");

// 延遲 2 秒鐘
DelayMs(2000);

// 初始化 ADC、DAC 和 PWM
init_adc();
init_dac();
init_pwm();

// 設置初始電壓和電流值
int voltage_setting = 10; // 初始電壓值為 1V
int current_setting = 5; // 初始電流值為 50mA

// 顯示初始電壓和電流值
display_voltage(voltage_setting);
display_current(current_setting);

// 進入主循環
while (1)
{
    // 讀取 ADC 的電壓值和電流值
    int voltage = read_adc(VOLTAGE_CHANNEL);
    int current = read_adc(CURRENT_CHANNEL);

    // 計算實際電壓和電流值
    float actual_voltage = voltage * ADC_VOLTAGE_REF / ADC_RESOLUTION;
    float actual_current = current * ADC_VOLTAGE_REF / ADC_CURRENT_GAIN / ADC_RESOLUTION;

    // 比較實際電壓和設置值,調整 PWM 的 Duty Cycle
    if (actual_voltage > voltage_setting)
    {
        int duty_cycle = (int)(PWM_PERIOD * voltage_setting / actual_voltage);
        SetDCOC2PWM(duty_cycle);
        SetDCOC3PWM(0);
    }
    else
    {
        int duty_cycle = (int)(PWM_PERIOD * current_setting / actual_current);
        SetDCOC2PWM(0);
        SetDCOC3PWM(duty_cycle);
    }

    // 顯示實際電壓和電流值
    char buf[17];
    sprintf(buf, "V: %4.2fV I: %4.2fmA", actual_voltage, actual_current);
    LcdSetCursor(0, 0);
    LcdWriteString(buf);

    // 檢查是否按下按鈕,如果按下了按鈕則切換電壓和電流設置值
    if (ButtonPressed())
    {
        if (voltage_setting > 1)
        {
            voltage_setting--;
            current_setting++;
        }
        else
        {
            voltage_setting = 10;
            current_setting = 5;
        }
        display_voltage(voltage_setting);
        display_current(current_setting);
    }

    // 延遲 100 毫秒
    DelayMs(100);
}

return 0;
}

// 初始化 ADC
void init_adc()
{
// 設置 ADC 的時鐘頻率
ADCCON3bits.ADCSEL = 0b000; // 設置 ADC 時鐘源為 PBCLK3
ADCCON3bits.CONCLKDIV = 0b000; // 設置 ADC 時鐘頻率為 PBCLK3/1 = 40MHz

// 設置 ADC 輸入通道
ADCCON2bits.CH0SA = VOLTAGE_CHANNEL; // 設置 CH0 的輸入通道為電壓通道
ADCCON2bits.CH0NA = 0b00000; // 設置 CH0 的負輸入為 AVSS

ADCCON2bits.CH123SA = CURRENT_CHANNEL; // 設置 CH1、CH2、CH3 的輸入通道為電流通道
ADCCON2bits.CH123NA = 0b00000; // 設置 CH1、CH2、CH3 的負輸入為 AVSS

// 設置 ADC 的採樣時間和轉換時鐘
ADCCON1bits.SAMC = 0b11111; // 設置採樣時間為 31 Tad
ADCCON3bits.ADCS = 0b00000001; // 設置轉換時鐘為 Tpb/2 = 20MHz

// 啟用 ADC
ADCCON1bits.ADON = 1;
}

// 讀取 ADC 的值
int read_adc(int channel)
{
// 選擇 ADC 的輸入通道
ADCCON2bits.CH0SA = channel;

// 啟動 ADC 轉換
ADCCON1bits.SAMP = 1;
DelayUs(10);
ADCCON1bits.SAMP = 0;
while (!ADCDSTAT1bits.RDY0);

// 讀取 ADC 的值
int value = ADCDATA0;

return value;
}

// 初始化 DAC
void init_dac()
{
// 設置 DAC 的時鐘頻率
DACCTRLbits.CLKSEL = 0b000; // 設置 DAC 的時鐘源為 PBCLK3
DACCTRLbits.CLKDIV = 0b000; // 設置 DAC 的時鐘頻率為 PBCLK3/1 = 40MHz


// 設置 DAC 的輸出電壓
SetDCODAC(0, 0); // CH0 設置為 0V
SetDCODAC(1, DAC_RESOLUTION); // CH1 設置為 3.3V

// 啟用 DAC
DACCTRLbits.DACEN = 1;
}

// 初始化 PWM
void init_pwm()
{
// 設置 PWM 的時鐘頻率
PCLKCONbits.PCLKDIV = 0b000; // 設置 PWM 的時鐘頻率為 PBCLK3/1 = 40MHz
// 設置 PWM 輸出的引腳
TRISBbits.TRISB9 = 0; // 將 RB9 設置為輸出
RPOR4bits.RP8R = 0b101110; // 將 RP8 連接到 PWM1H

// 設置 PWM 的周期和占空比
PWM1CON1bits.ITB = 0; // 設置 PWM 的時間基準為 PBCLK3
PWM1CON1bits.MTBS = 0; // 設置 PWM 的單位時間為 TCY(Tpb/2)
PWM1CON1bits.PMOD1 = 0b00; // 設置 PWM1 的輸出模式為獨立模式
PWM1CON1bits.PEN1H = 1; // 啟用 PWM1H 的輸出

PWM1PH = 0x00; // 設置 PWM 的相位為 0
PWM1DC = 0x00; // 設置 PWM 的占空比為 0
PWM1DCH = 0x00;
PWM1LDC = 0x00;
PWM1LDCH = 0x00;

PWM1PR = PWM_PERIOD; // 設置 PWM 的周期為 40KHz
PWM1TMR = 0x00; // 將 PWM 計時器清零

// 啟用 PWM
PWM1CON1bits.PEN1H = 1;
PWM1CON1bits.PEN1L = 0;
PWM1CON1bits.PEN2H = 0;
PWM1CON1bits.PEN2L = 0;

PWM1CON2bits.UDIS = 0; // 啟用更新電路
PWM1CON2bits.OSYNC = 0; // 當更新 PWM 周期或占空比時不同步
PWM1CON2bits.IUE = 1; // 立即更新 PWM 的周期和占空比

PWM1CON1bits.PEN1H = 1; // 啟用 PWM1H 的輸出
}

// 設置 DAC 的輸出電壓
void set_dac_voltage(float voltage)
{
// 將輸入電壓轉換成 DAC 的輸出數字
int dac_value = (int)(voltage / VREF * DAC_RESOLUTION);
// 將 DAC 的輸出設置為指定的數字
SetDCODAC(0, dac_value);
}

// 設置 PWM 的占空比
void set_pwm_duty_cycle(float duty_cycle)
{
// 將輸入的占空比轉換成 PWM 的數值
int pwm_value = (int)(duty_cycle / 100 * PWM_PERIOD);
// 將 PWM 的占空比設置為指定的數值
PWM1DC = pwm_value;
PWM1DCH = (pwm_value >> 8) & 0xFF;
PWM1LDC = pwm_value;
PWM1LDCH = (pwm_value >> & 0xFF;
}
// 主程序
int main(void)
{
// 設置 CPU 頻率
SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
// 設置 ADC 和 DAC
init_adc();
init_dac();

// 設置 PWM
init_pwm();

// 設置初始的電壓和電流值
float target_voltage = 0.0;
float target_current = 0.0;

// 主循環
while (1)
{
    // 讀取 ADC 的值
    float adc_voltage = read_adc_voltage();
    float adc_current = read_adc_current();

    // 計算電壓和電流誤差
    float voltage_error = target_voltage - adc_voltage;
    float current_error = target_current - adc_current;

    // 調整 PWM 的占空比
    float pwm_duty_cycle = pwm_duty_cycle + voltage_error * KP_VOLTAGE - current_error * KP_CURRENT;
    set_pwm_duty_cycle(pwm_duty_cycle);

    // 調整 DAC 的輸出電壓
    float dac_voltage = dac_voltage + voltage_error * KP_VOLTAGE;
    set_dac_voltage(dac_voltage);

    // 等待一段時間
    delay_ms(10);
}

return 0;
}


這是基本的程式碼框架
具體的細節和一些函數定義需要根據你的具體硬體和需求進行修改和實現。




歡迎光臨 冰楓論壇 (https://bingfong.com/) Powered by 冰楓