切换到宽版
  • 2619阅读
  • 5回复

[C51]求助 PWM调压程序 [复制链接]

上一主题 下一主题
离线lern
 

发帖
81
M币
18
专家
0
粉丝
7
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2018-12-14
一个PWM调压程序,其中按键调节程序,小数点后的数字大于设定值还可以往上调,是什么原因?望大老们给予指点,谢谢!另:怎么利用PID来调节电压?也望大老能指点,十分地感谢!


附程序:

#include "stc12c5a60s2.h"                                                  
#include "intrins.h"  

#define ADC_POWER   0x80  //ADC电源控制位,0-关闭,1-打开
#define ADC_FLAG    0x10  //ADC结束标志位
#define ADC_START   0x08  //ADC启动控制位
#define ADC_SPEEDLL 0x00  //540 clocks--选择转换速度
unsigned char Lcd_Dis1_table[] = {"SetValue:       "};     //第一行显示框架
unsigned char Lcd_Dis2_table[] = {"Voltage :       "};     //第二行显示框架

float Show, NUM;
unsigned char volt = 0;  //作为显示的数据
bit flag300ms = 1;       //300ms定时标志
unsigned char T0RH = 0;  //T0重载值的高字节
unsigned char T0RL = 0;  //T0重载值的低字节
                                                  //PID算法公式:
sbit key1 = P2^7;        //定义按键1
sbit key2 = P2^6;        //定义按键2
sbit key3 = P2^5;        //定义按键3
sbit key4 = P2^4;        //定义按键4
sbit key_gnd = P2^3;     //定义接地

void ConfigTimer0(unsigned int ms);
void InitADC();
void InitPWM();
void PWM0_change(unsigned char type, unsigned char change);
void Delay(unsigned int n);
void  KeyAction(unsigned char keycod);
void NumToString(unsigned char num);
void ValueToString(unsigned char *str, unsigned int val);
unsigned int GetADCResult(unsigned char ch); //读取输入电压模数转换函数

extern void KeyScan();
extern void KeyDriver();
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

void main()
{
    unsigned int val;
    unsigned char str[10];

    key_gnd = 0;
    EA = 1;            //开总中断
    ConfigTimer0(10);  //配置T0定时10ms
    InitADC();
    InitPWM();
    InitLcd1602();
    LcdShowStr(0, 0, Lcd_Dis1_table);
    LcdShowStr(0, 1, Lcd_Dis2_table);
    while(1)
    {
        KeyDriver();        
        if(flag300ms)
        {
            flag300ms = 0;
            val = GetADCResult(7);
            ValueToString(str, val);
            LcdShowStr(9, 1, str);
        }
        NumToString(volt);
/*        NUM = 10 * NUM;        
        Show = ldata;
        if((NUM < (Show - 0.1))||(NUM > (Show + 0.1)))
        {          
            if(NUM < (Show - 0.1))
            {
                if((Show - 0.1) - NUM > 1)
                {
                    PWM1_change(1, 0X05);
                }
                else
                {
                    PWM1_change(1, 0X01);
                }
            }
            else
            {
                if(NUM - (Show + 0.1) > 1)
                {
                    PWM1_change(0, 0X05);
                }
                else
                {                                                  
                    PWM1_change(0, 0X01);
                }
            }
            Delay(500);
        }                
        else
        {
            Delay(2000);
        }           */
    }
}

void NumToString(unsigned char num)
{
    unsigned char str[10];

    str[0] = num/100 + '0';
    str[1] = num/10%100 + '0';
    str[2] = '.';
    str[3] = num%10 + '0';
    str[4] = 'V';
    str[5] = '\0';
    LcdShowStr(9, 0, str);
}
/*------------ADC 取值 --------------*/
unsigned int GetADCResult(unsigned char ch)     //ch--AD输入通道
{
    unsigned int val = 0;

    ADC_CONTR =    ADC_POWER | ADC_SPEEDLL | ADC_START |ch;
    _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
    while(!(ADC_CONTR & ADC_FLAG));       //等待AD转换完成
    ADC_CONTR &= ~ADC_FLAG;               //关闭ADC
    val = ADC_RES;
    val = (val << 2) | (0x03 & ADC_RESL);

    return val;   //返回A/D转换结果
}

void InitADC()
{
    P1ASF = 0x80;         //设置P1.7为AD输入通道
    ADC_RES = 0;         //清除高8位RES和低2位RESL
    ADC_RESL = 0;
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
    Delay(20);          //打开ADC电源并延时
}
/* ADC转换值转为实际电压值的字符串形式,str-字符串指针,val-AD转换值 */
void ValueToString(unsigned char *str, unsigned int val)
{
    NUM = (val * 5.03) / 1024.0;

    str[0] = (unsigned int)NUM/10 + '0';
    str[1] = (unsigned int)NUM%10 + '0';
    str[2] = '.';
    str[3] = (unsigned int)(NUM*10)%10 + '0';
    str[4] = (unsigned int)(NUM*100)%10 + '0';
    str[5] = 'V';
    str[6] = '\0';        
}

void InitPWM()
{
    CCON = 0;        //Initial PCA control register
                    //PCA timer stop runing
                    //Clear CF flag
                    //Clear all module interrupt flag
    CL = CH = 0;    //Reset PCA base timer
    CMOD = 0x02;     //Set PCA timer clock source as Fousc/2    0X00:以系统时钟/12 为时钟源,0X02:系统时钟/2,0x08:系统时钟
                    //Disable PCA timer overflow interrupt
    CCAP0L = CCAP0H = 0xff;     //起始占空比,0XC0:占空比为25%,0X80:占空比为50%,0X40:占空比为75%
    PCA_PWM0 = 0x00;
    CCAPM0 = 0x42;//0X42:8位PWM P1.4输出,无中断;0X53:8位PWM输出,下降沿产生中断;0X63:上升沿产生中断;0X73:跳变沿产生中断
    CR = 1;    //计时器开始工作
}

void PWM0_change(unsigned char type, unsigned char change) //type=0减占空比,1增加占空比 change: 0X0C约5%,0X05约2%
{
   if(type == 0)
   {  
        if(CCAP0L < 0xff) //占空比 < 90%
        {
            CCAP0L += change;
            CCAP0H += change;
        }
   }                
   else
   {    
           if(CCAP0L > 0x00)  // > 10%              
        CCAP0L -= change;
        CCAP0H -= change;                        
   }  
}

void  KeyAction(unsigned char keycod)
{
    switch(keycod)
    {
        case 0x26:
            if(volt < 50);
            {
                volt++;
                PWM0_change(1, 0x05);
            }
            break;
        case 0x28:
            if(volt > 0)
            {
                volt--;
                PWM0_change(0, 0x05);
            }
            break;
        
        case 0x27:
            if(volt < 50)
            {
                volt += 10;
                PWM0_change(1, 0x0C);
            }
            break;
        case 0x25:
            if(volt > 0)
            {
                volt -= 10;
                PWM0_change(0, 0x0C);
            }
            break;          
        default: break;
    }
}

void Delay(unsigned int n)                                                                                
{
    unsigned int x;

    while (n--)
    {
       x = 500;
       while (x--);
    }
}
/*
void DelayMs(unsigned char ms) //延时程序
{      
    unsigned int i;

    while(ms--)
    {
       for(i=0; i<850; i++)
               ;
    }
}
     */
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;  //临时变量
    
    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 12;           //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
/* T0中断服务函数,执行300ms定时 */
void InterruptTimer0() interrupt 1
{
    static unsigned char tmr300ms = 0;
    
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
    KeyScan();
    tmr300ms++;
    if (tmr300ms >= 30)  //定时300ms
    {
        tmr300ms = 0;
        flag300ms = 1;
    }
}
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
离线devcang

发帖
18104
M币
9149
专家
20
粉丝
97
只看该作者 1楼 发表于: 2018-12-14
请登录后查看
本帖最近打赏记录:共1条打赏 ,专家+1
阿睦 专家 +1 熱心助人 2018-12-14
离线lern

发帖
81
M币
18
专家
0
粉丝
7
只看该作者 2楼 发表于: 2018-12-14
回 devcang 的帖子
请登录后查看
离线lern

发帖
81
M币
18
专家
0
粉丝
7
只看该作者 3楼 发表于: 2018-12-14
回 devcang 的帖子
请登录后查看
离线595953427@qq

发帖
610
M币
51
专家
0
粉丝
15
只看该作者 4楼 发表于: 2018-12-14
回 devcang 的帖子
请登录后查看
离线腾龙科技

发帖
294
M币
1841
专家
12
粉丝
20
只看该作者 5楼 发表于: 2018-12-15
回 devcang 的帖子
请登录后查看
快速回复
限80 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个