用是STCD 15W404AS 做主控,片内资源用到了,可调PWM,ADC , 串口(用来读取计量模块的数据),具体功能,可按键调充电功率,1602显示实时电压,电流,功率,电能累计,
设计有1602显示,但是不知道时序写的还有些问题还是干扰问题,充电的时候就白屏了或者乱码了,,不充电有时候有时候是正常的,这里还需要调试,目前已经正常充电,电流30A
单片机源程序如下:
- #include <reg52.h>
- #include "intrins.h"
- sfr AUXR = 0x8E; //0000,0000 辅助寄存器
- sfr T2H = 0xD6; //0000,0000 T2高字节
- sfr T2L = 0xD7; //0000,0000 T2低字节
- sfr P0M1 = 0x93;
- sfr P0M0 = 0x94;
- sfr P1M1 = 0x91;
- sfr P1M0 = 0x92;
- sfr P2M1 = 0x95;
- sfr P2M0 = 0x96;
- sfr P3M1 = 0xb1;
- sfr P3M0 = 0xb2;
- sfr P4M1 = 0xb3;
- sfr P4M0 = 0xb4;
- sfr P5M1 = 0xC9;
- sfr P5M0 = 0xCA;
- sfr P6M1 = 0xCB;
- sfr P6M0 = 0xCC;
- sfr P7M1 = 0xE1;
- sfr P7M0 = 0xE2;
- /////////////////////////////////////////////////////////////////////////////////////////////
- //PWM模块寄存器定义
- sfr P_SW1 = 0xA2; //外设功能切换寄存器1 针脚选择功能寄存器
- #define CCP_S0 0x10 //P_SW1.4 选择针脚功能
- #define CCP_S1 0x20 //P_SW1.5 选择针脚功能
- #define S1_S1 0x80 //P_SW3.6 选择针脚功能
- #define S1_S0 0x40 //P_SW3.7 选择针脚功能
- sfr ADC_CONTR = 0xBC; //ADC控制寄存器
- sfr ADC_RES = 0xBD; //ADC高8位结果
- sfr ADC_LOW2 = 0xBE; //ADC低2位结果
- sfr P1ASF = 0x9D; //P1口第2功能控制寄存器
- #define ADC_POWER 0x80 //ADC电源控制位
- #define ADC_FLAG 0x10 //ADC完成标志
- #define ADC_START 0x08 //ADC起始控制位
- #define ADC_SPEEDLL 0x00 //540个时钟
- #define ADC_SPEEDL 0x20 //360个时钟
- #define ADC_SPEEDH 0x40 //180个时钟
- #define ADC_SPEEDHH 0x60 //90个时钟
-
- sfr CCON = 0xD8; //PCA控制寄存器
- sbit CCF0 = CCON^0; //PCA模块0中断标志
- sbit CCF1 = CCON^1; //PCA模块1中断标志
- sbit CR = CCON^6; //PCA定时器运行控制位
- sbit CF = CCON^7; //PCA定时器溢出标志
- sfr CMOD = 0xD9; //PCA模式寄存器
- sfr CL = 0xE9; //PCA定时器低字节
- sfr CH = 0xF9; //PCA定时器高字节
- sfr CCAPM0 = 0xDA; //PCA模块0模式寄存器
- sfr CCAP0L = 0xEA; //PCA模块0捕获寄存器 LOW
- sfr CCAP0H = 0xFA; //PCA模块0捕获寄存器 HIGH
- sfr CCAPM1 = 0xDB; //PCA模块1模式寄存器
- sfr CCAP1L = 0xEB; //PCA模块1捕获寄存器 LOW
- sfr CCAP1H = 0xFB; //PCA模块1捕获寄存器 HIGH
- sfr CCAPM2 = 0xDC; //PCA模块2模式寄存器
- sfr CCAP2L = 0xEC; //PCA模块2捕获寄存器 LOW
- sfr CCAP2H = 0xFC; //PCA模块2捕获寄存器 HIGH
- sfr PCA_PWM0 = 0xf2; //PCA模块0的PWM寄存器
- sfr PCA_PWM1 = 0xf3; //PCA模块1的PWM寄存器
- sfr PCA_PWM2 = 0xf4; //PCA模块2的PWM寄存器
- ///////////////////////////////////////////////////////////函数列表、、、、、、、、、、、、、、、、、、、、、、、、、、、
- void UartInit(); //初始化串口
- void Timer0Init(); //初始化T0
- void UartWxd(); //发送数据查询实时信息
- void jiexibuf(); //解析接受到的数据
- void pwm(); //解析接受到的数据
- void InitADC(); //初始化ADC
- void GetADCResult(); //读取ADC的值存储在变量adc里面
- void Delay(unsigned int n); //软件延时 1.6毫秒左右
- void chongdian(); // 充电流程
- void diannengjisuan();//J计算初始电能并计算已用电能
- void dianliuxuanze(); //按钮选项电流
- ///////////////////////////////////////////////////////////定义的一些变量、、、、、、、、、、、、、、、、、、、、、、、、、、、
- bit flagTxd = 0; //单字节发送完成标志,用来替代 TXD 中断标志位
- sbit s1 = P3^3; //切换继电器
- sbit km = P3^2; //功率继电器接触器
- sbit pwmdip = P1^1;
- sbit k1 = P3^0; //按钮
- //sbit LED = P1^2;
- unsigned char cntRxd = 0; //接收字节计数器
- unsigned char pdata bufRxd[30]; //接收字节缓冲区
- unsigned char code bufWxd[8] ={0x01,0x03,0x00,0x48,0x00,0x0A,0x45,0xDB,};//发送的数据 增加了code关键字,此数组写在程序区减少使用内部内存128K
- unsigned long pdata cnt = 0; //毫秒计数
- unsigned long pdata sec; //秒计数
- //unsigned cha *but;// 发送指针
- unsigned int pdata vcc; // 电压
- unsigned int pdata vci; // 电流
- unsigned int pdata power; // 功率
- unsigned long pdata kwh=0; // 电能
- unsigned long pdata kwh1; // 初始电能
- unsigned char pw; //设定的空占比%
- unsigned char cp; //充电桩PWM波形 cp电压采集信号 120
- //// 关于LCD 1602 /////////////////LCD的一些定义
- sfr P5 = 0xC8;
- unsigned char pdata lcd1[16]; //LCD第一行
- unsigned char pdata lcd2[16]; //LCD第二行
- sbit LCD1602_RS = P5^5; //命令、数据选择 H\L
- sbit LCD1602_E = P5^4; //使能
- unsigned char pdata ki; //电流显示1表示16A 2表示32A
- #define LCD1602_DATAPINS P1 //定义P1口为数据端
- void LcdWriteCom(unsigned char com); /*LCD1602写入8位数据子函数*/
- void LcdWriteData(unsigned char dat); /*LCD1602写入8位数据子函数*/
- void LcdInit(); /*LCD1602初始化子程序*/
- void lcd1602(); //1602显示刷新
- void Lcd1602_Delay5ms();
- void Lcd1602_Delay1ms();
- void main(){
- P0M0 = 0x00;
- P0M1 = 0x00;
- P1M0 = 0x00;
- P1M1 = 0x00;
- P2M0 = 0x00;
- P2M1 = 0x00;
- P3M0 = 0x00;
- P3M1 = 0x00;
- P4M0 = 0x00;
- P4M1 = 0x00;
- P5M0 = 0x00;
- P5M1 = 0x00;
- P6M0 = 0x00;
- P6M1 = 0x00;
- P7M0 = 0x00;
- P7M1 = 0x00;
- P_SW1=P_SW1|S1_S0;
- EA = 1; //使能总中断
- ES = 1; //使能串口1中断
- UartInit(); //初始化串口
- pwm(); //初始化pwm模块设置
- InitADC(); //初始化ADC
-
- Timer0Init(); //初始化T0
- LcdInit();//初始化lcd
-
- while (1){
- chongdian(); //充电流程
- dianliuxuanze(); //电流选择函数
-
- if(TF0==1){ //t0溢出的次数
- cnt++;}
- if(pwmdip==1){ //检测
- GetADCResult(); //读取刷新ADC的值 cp就是读取的8位电压信号
-
- }
- if(cnt>=20000){ //大概1秒钟,还可以调整
-
- cnt=0;
- sec++;
-
- UartWxd(); //发送电能模块读取命令
- jiexibuf(); //解析接受到的数据
- diannengjisuan(); //电能计算函数
- lcd1602(); //lcd显示
- }
-
- } }
- void chongdian(){ //、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、充电流程
- if(cp>111){ //当cp电压大于11.1时 状态1
- s1=1; //小接触器不吸合 常闭点12V s1
- km=1;
- } //主接触器不吸合
- if(98>cp && cp>81){ //当cp电压大于8.1V小于9.8时 状态2 与车辆已连接
- s1=0; //小接触器吸合 切换至PWM
- km=1; } //主接触器不吸合
- if(66>cp && cp>51){ //当cp电压大于5.1小于6.6时 状态3 充电中
- s1=0; //小接触器吸合 切换至PWM
- km=0; //主接触器吸合 开始充电
-
- }
- }
- void dianliuxuanze(){ //电流选择初始值16A
- bit i=0; //电流选择初始值16A
- if (i==1){ //不切换电流16A
- pw=33;
- ki=1;}
- else{pw=60;
- ki=2;} // 切换电流32A
- if(k1==0)
- { Lcd1602_Delay5ms();
- Lcd1602_Delay5ms();
- if(k1==0){
- i=!i;//k1按下置反i
- }
-
- }
- }
- void pwm(){ //PWM程序、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
-
- ACC = P_SW1; //累加器 等于外设寄存器
- ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=0 CCP_S1=0
- P_SW1 = ACC; //(P1.2/ECI, P1.1/CCP0, P1.0/CCP1, P3.7/CCP2) 读取累加器的值写进外设寄存器
- CCON = 0; //初始化PCA控制寄存器
- //PCA定时器停止
- //清除CF标志
- //清除模块中断标志
- CL = 0; //复位PCA寄存器
- CH = 0;
- CMOD = 0x04;
- // CMOD = 0x04; //设置PCA时钟源 t0定时器
- //禁止PCA定时器溢出中断
- PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM
- CCAP0H = CCAP0L =255-255*60/100; //PWM0的占空比为87.5% ((100H-20H)/100H) 255-255*设定空占比 /100
- CCAPM0 = 0x42; //00101010 PCA模块0允许比较功能 使用CCP0脚为可调脉冲输出 P1.1
- }
- void Timer0Init() //T0作为PWM频率基准发生
- {
-
- AUXR |= 0x80; //定时器时钟1T模式
- TMOD &= 0xF0; //设置定时器模式
- TL0 = 0xd5; //设置定时初值 计算方法,65536-晶振/(256*需要频率)
- TH0 = 0xFf; //设置定时初值
- TR0 = 1; //定时器0开始计时
- ET0 =0; // 禁止T0中断
- TF0 = 0; //清除TF0标志
- // EA =0; 关闭总总中断
- CR = 1; } //PCA定时器开始工作
- ///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // AUXR |= 0x80; //定时器时钟1T模式
- // TMOD &= 0xF0; //设置定时器模式
- // TL0 = 0xff; //设置定时初值
- // TH0 = 0xf6; //设置定时初值
- // TF0 = 0; //清除TF0标志
- // TR0 = 1; //定时器0开始计时
- /*----------------------------
- 初始化ADC
- ----------------------------*/
- void InitADC() //初始化ADC
- {
- P1ASF = 0x01; //设置P1.0口为AD口
- ADC_RES = 0; //清除结果寄存器
- ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
- Delay(2); //ADC上电并延时
- }
- /*----------------------------
- 读取ADC结果
- ----------------------------*/
- void GetADCResult()
- { unsigned long y;
- ADC_CONTR = ADC_POWER | ADC_SPEEDLL | 0 | ADC_START; //ADC电源 540个时钟ADC_SPEEDHH ADC_SPEEDLL 通道号 启动
- _nop_(); //等待4个NOP
- _nop_();
- _nop_();
- _nop_();
- while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
- ADC_CONTR &= ~ADC_FLAG; //Close ADC
-
- //实际滤波测得4.6V一下不予处理
- if(ADC_RES>0x64){
- y=12000000/256*(ADC_RES+1); //ADC结果转换 单位是最大12000毫伏
- cp=y/100000; //结果转换120v 放大10倍最大电压
- }
- }
- void jiexibuf() //解析接受到的数据
- { unsigned long h;
- unsigned long j;
- unsigned long l;
- unsigned long o;
- vcc = (bufRxd[3]<<8)| bufRxd[4]; //电压 int16位
- vci = (bufRxd[5]<<8)| bufRxd[6]; //电流 int16位
- power = (bufRxd[7]<<8)| bufRxd[8]; //功率 int16位
- h = (bufRxd[9]<<8)| bufRxd[10];//电能 32位数据高16位
- j = (bufRxd[11]<<8)|bufRxd[12];//电能 32位数据低16位
- l = h<<16;
- o = (l|j)*100;
- kwh = o/3200;
- }
- void diannengjisuan() //计算电能显示函数
- { unsigned long x;
- static bit p=1;
-
- if(p==1){ //开始初始电能记录
- if(s1==0){ //刷新是否有电能数据
- x=kwh1; // 初始电能传给x
- p=0; //退出初始电能记录
- }
- }
- // kwh=kwh1-x;
- }
- void UartInit() //4800bps@11.0592MHz
- {
- // P_SW1=P_SW1|S1_S0;
- SCON = 0x50; //8位数据,可变波特率
- AUXR |= 0x01; //串口1选择定时器2为波特率发生器
- AUXR |= 0x04; //定时器2时钟为Fosc,即1T
- T2L = 0xC0; //设定定时初值
- T2H = 0xFD; //设定定时初值
- AUXR |= 0x10; //启动定时器2
- }
- void UartWxd(){
- unsigned char u; //数据位置 bufWxd[u]
- for(u=0;u<=7;u++)
- {
- flagTxd=0;
- SBUF=bufWxd[u]; // SBUF=bufWxd[u];
- while(!flagTxd);
-
- }
- }
- /*----------------------------
- 软件延时
- ----------------------------*/
- void Delay(unsigned int n)
- {
- unsigned int x;
- while (n--)
- {
- x = 5000;
- while (x--);
- }
- }
- void InterruptUART() interrupt 4{
- if (RI){ //接收到字节
- RI = 0; //手动清零接收中断标志位
- bufRxd[cntRxd++] = SBUF; //接收的数据存到接收缓冲区,数组
- if(cntRxd==25){ //接收24帧数据,然后复位接收计数器,下次从0开始接收
- cntRxd=0;
- }
- }
- if (TI){ //字节发送完毕
- TI = 0; //手动清零发送中断标志位
- flagTxd = 1; //设置字节发送完成标志
- }
- }
- //清中断标志/清中断标志
- //void PCA_isr() interrupt 7
- //{
- // CCF0 = 0; //清中断标志
- // CCAP0L = value;
- // CCAP0H = value >> 8; //更新比较值
- // value += T100Hz;
- // if (cnt-- == 0)
- // {
- // cnt = 100; //记数100次
- // PCA_LED = !PCA_LED; //每秒闪烁一次
- // }
- //}
- //// 关于LCD 1602 LCD 1602 LCD 1602 LCD 1602 LCD 1602 LCD 1602 LCD 1602 /////////////////LCD的一些定义
- void LcdWriteCom(unsigned char com) //写入命令
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 0; //选择写入命令
- LCD1602_DATAPINS = com >>2; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
- Lcd1602_Delay1ms();
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay5ms();
- LCD1602_E = 0;
- LCD1602_DATAPINS = com << 2; //发送低四位
- Lcd1602_Delay1ms();
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay5ms();
- LCD1602_E = 0;
- }
- void LcdWriteData(unsigned char dat) //写入数据
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //选择写入数据
- // LCD1602_RW = 0; //选择写入
-
-
- LCD1602_DATAPINS = dat >>2; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
- Lcd1602_Delay1ms();
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay5ms();
- LCD1602_E = 0;
- LCD1602_DATAPINS = dat << 2; //写入低四位
- Lcd1602_Delay1ms();
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay5ms();
- LCD1602_E = 0;
- }
- void LcdInit() //LCD初始化子程序
- {
- Delay(20);
- LcdWriteCom(0x32); //将8位总线转为4位总线
- LcdWriteCom(0x28); //在四位线下的初始化
- LcdWriteCom(0x0c); //开显示不显示光标
- LcdWriteCom(0x06); //写一个指针加1
- LcdWriteCom(0x01); //清屏
- //LcdWriteCom(0x80); //设置数据指针起点
- }
- void lcd1602()
- { LcdWriteCom(0x80); //设置数据指针起点
- LcdWriteData('V');
- LcdWriteData(':');
- LcdWriteData('0'+vcc/10000%10);
- LcdWriteData('0'+vcc/1000%10);
- LcdWriteData('0'+vcc/100%10);
- LcdWriteData('.');
- LcdWriteData('0'+vcc/10%10);
- LcdWriteData('0'+vcc%10);
- LcdWriteData(' ');
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有程序51hei提供下载:
485 - 通讯程序加显示.zip
(53.37 KB, 下载次数: 127)
|