在這個論壇上很久第一次發(fā)帖子,之前在數碼之家發(fā)表過,17做的東西 先分享給大家共同討論
前一段時間開源了一個智能小車,小車需要鋰電池供電,家里一大堆電池,當使用的時候才發(fā)現好久沒有容量大減,正好最近在研究labview,所以就做了1個來測試一下電池容量,其實原理非常簡單,用單片機就能輕松搞定,為了高大上而且能為了能看到電池充電和放電的曲線所以就需要上位軟件了,第一次用labview編程程序寫的非常爛高手見諒了
功能:
上位機 labview 負責采集數據計時顯示設置充放電截止電壓和電池曲線圖
下位機 stc125a60s2 負責ad檢測電壓電流串口通信
1.增加1602液晶,方便沒有電腦的時候也可以測量電池容量
2.使用labview工作,電壓電流同時顯示在1602上面
1秒鐘刷新一次電壓,電流,容量,時間
由于手底下沒有mos管所以暫時使用317進行橫流放電
充電采用鋰電池專用模塊
通信 串口發(fā)送字符串
檢測電壓電流 Work_v_ad
充電 Work_v_cd
放電 Work_v_fd
關閉 Work_voff
電腦和單片機通信采用一個usb ttl下載器進行
ad采集為了準確,采用Tl431做標準基準源,還算比較準確的
電路圖
沒有上位軟件也能顯示容量,只不過沒有曲線
程序
- #include<stc12c5a60s2.h>
- #include"stdio.h"
- #include"intrins.h"
- #define uint unsigned int
- #define uchar unsigned char
- sbit v_cd=P2^0;
- sbit v_fd=P2^1;
- sbit key=P2^2;
- sbit lcdrs=P2^3;
- sbit lcden=P2^4;
- int volt,aolt,curr,mah;
- uchar key_flag=1;
- uchar num;
- uchar v_shi,v_ge,v_xiao1,v_xiao2;
- uchar a_shi,a_ge,a_xiao1,a_xiao2;
- uchar h_shi,h_ge,h_xiao1,h_xiao2;
- uchar t_shi,t_ge,t_xiao1,t_xiao2;
- uchar s,g,x1,x2;
- uchar data table[12]; //暫存數組,可以將10改為你需要的數值
- uint i=0;
- uchar code table1[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
- bit com_flag;
- uint time;
- uint num1,num2;
- bit time_flag;
- bit shan_flag;
- bit lcd_flag;
- void AD_init();
- unsigned int AD_get(unsigned char channel);
- float AD_work(unsigned char channel);
- void delayms(uint z);
- void delay(unsigned int a); //延時約1ms
- void UART_init(void); //初始化函數
- void senddata(uchar dat);
- //void uart_sendstring(uchar *upStr);
- void write_com(uchar com) ;
- void write_data(uchar date);
- void lcd_init();
- void time_init();
- void delayms(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- /**********************************************************/
- void UART_init(void) //初始化函數
- {
- SCON = 0x50;
- TMOD = 0x21;
- TH1 = 0xFD; //波特率9600
- TL1 = 0xFD;
- TR1 = 1;
- ES = 1;
- EA = 1;
- // TI =0;
- // REN = 1;
- }
- /**********************************************************/
- void senddata(uchar dat)
- {
- ES = 0; //關串口中斷
- TI = 0; //將串口發(fā)送完成中斷請求標志清零
- SBUF = dat; //寫數據到發(fā)送緩沖區(qū)
- while(!TI); //等待發(fā)送完成
- TI = 0; //將串口發(fā)送完成中斷請求標志清零
- ES = 1; //將串口發(fā)送完成中斷請求標志清零
- }
- /* ***************************************************** */
- // 函數名稱:UART_SendString()
- // 函數功能:發(fā)送字符串
- // 入口參數:待發(fā)送的字符串(*upStr)
- // 出口參數:無
- /* ***************************************************** *
- void uart_sendstring(uchar *upStr)
- {
- while(*upStr) // 檢測是否發(fā)送完畢
- {
- senddata(*upStr++);
- // 調用UART_SendOneByte函數一個字節(jié)一個字節(jié)發(fā)送數據
- }
- }
- /* ***************************************************** */
- void delay(unsigned int a) //延時約1ms
- {
- unsigned int i;
- while (--a!=0)
- for(i=600;i>0;i--); //1T單片機i=600,若是12T單片機i=125
- }
- /*************************************************************/
- void write_com(uchar com) //1602 lcd
- {
- lcdrs=0;
- lcden=1;
- P0=com;
- delayms(5);
- lcden=0;
- }
- /**********************************************************/
- void write_data(uchar date) //1602 lcd
- {
- lcdrs=1;
- lcden=1;
- P0=date;
- delayms(5);
- lcden=0;
- }
- /**********************************************************/
- void lcd_init() //lcd初始化
- {
- write_com(0x38);
- delayms(20);
- write_com(0x38);
- delayms(20);
- write_com(0x0c);
- delayms(20);
- write_com(0x06);
- delayms(20);
- write_com(0x01);
- delayms(20);
- }
- void AD_init()
- {
- P1ASF=0xff; //P1口全部作為模擬功能AD使用
- ADC_RES=0; //清零轉換結果寄存器高8位
- ADC_RESL=0; //清零轉換結果寄存器低2位
- ADC_CONTR=0x80;//開啟AD電源
- delay(2); //等待1ms,讓AD電源穩(wěn)定
- }
- void time_init()
- {
- TH0=(65536-45872)/256;
- TL0=(65536-45872)%256;
- EA=1;
- ET0=1;
- TR0=1;
-
- }
- void lcd_display()
- {
-
- volt=((AD_get(0)*2.5)/AD_get(7))*2*1000;
- v_shi=volt/1000;
- v_ge=volt%1000/100;
- v_xiao1=volt%100/10;
- v_xiao2=volt%10;
-
- write_com(0x82);
- write_data(table1[v_shi]);
- write_com(0x83);
- write_data('.');
- write_com(0x84);
- write_data(table1[v_ge]);
- write_com(0x85);
- write_data(table1[v_xiao1]);
- write_com(0x86);
- write_data(table1[v_xiao2]);
- write_com(0x87);
- write_data('V');
-
- aolt=(AD_get(2)*0.002)*1000;
- a_shi=aolt/1000;
- a_ge=aolt%1000/100;
- a_xiao1=aolt%100/10;
- a_xiao2=aolt%10;
-
- write_com(0x89);
- write_data(table1[a_shi]);
- write_com(0x8a);
- write_data('.');
- write_com(0x8b);
- write_data(table1[a_ge]);
- write_com(0x8c);
- write_data(table1[a_xiao1]);
- write_com(0x8d);
- write_data(table1[a_xiao2]);
- write_com(0x8e);
- write_data('A');
-
- write_com(0xC0);
- write_data(' ');
-
- h_shi=mah/1000;
- h_ge=mah%1000/100;
- h_xiao1=mah%100/10;
- h_xiao2=mah%10;
-
- write_com(0xc1);
- write_data(table1[h_shi]);
- write_com(0xc2);
- write_data(table1[h_ge]);
- write_com(0xc3);
- write_data(table1[h_xiao1]);
- write_com(0xc4);
- write_data(table1[h_xiao2]);
-
- write_com(0xc5);
- write_data('M');
- write_com(0xc6);
- write_data('A');
- write_com(0xc7);
- write_data('H');
-
- write_com(0xc8);
- write_data(' ');
- write_com(0xc9);
- write_data('T');
- write_com(0xca);
- write_data('=');
-
- t_shi=time/100;
- t_ge=time%100/10;
- t_xiao1=time%10;
- write_com(0xcb);
- write_data(table1[t_shi]);
- write_com(0xcc);
- write_data(table1[t_ge]);
- write_com(0xcd);
- write_data(table1[t_xiao1]);
- write_com(0xce);
- write_data('M');
-
- }
-
- // float AD_work(unsigned char channel)
- // {
- // float AD_val; //定義處理后的數值AD_val為浮點數
- // unsigned char i;
- // for(i=0;i<100;i++)
- // AD_val+=AD_get(channel); //轉換100次求平均值(提高精度)
- // AD_val/=100;
- // // AD_val=(AD_val*2.5)/1024; //AD的參考電壓是單片機上的5v,所以乘5即為實際電壓值
- // return AD_val;
- // }
- void keysean()
- {
- if(key==0)
- {
- delayms(500);
- if(key==0)
- {
- key_flag++;
- if(key_flag>3)
- key_flag=1;
- }
- while(!key);
- }
-
- if(key_flag==1)
- {
- v_fd=1;
- v_cd=1;
- write_com(0x80);
- write_data(' ');
- num1=0;
- time_flag=0;
- }
-
- if(key_flag==2)
- {
- v_fd=1;
- v_cd=0;
- time=0;
- mah=0;
-
- write_com(0x80);
- write_data('C');
- write_com(0x81);
- write_data(' ');
-
- }
-
- if(key_flag==3)
- {
- v_cd=1;
- v_fd=0;
- time_flag=1;
- if(shan_flag==0)
- {
- write_com(0x80);
- write_data('F');
- }
- else
- {
- write_com(0x80);
- write_data(' ');
- }
-
- volt=((AD_get(0)*2.5)/AD_get(7))*2*1000;
- v_shi=volt/1000;
- v_ge=volt%1000/100;
-
- if(v_shi==2)
- {
- v_fd=1;
- v_cd=1;
- time_flag=0;
- key_flag=1;
- }
-
- }
-
- }
- void main()
- {
- AD_init();
- UART_init();
- lcd_init();
- time_init();
- v_cd=1;
- v_fd=1;
-
- while(1)
- {
- if(com_flag==0)
- keysean();
- if(lcd_flag==1)
- {
- lcd_display();
- lcd_flag=0;
- }
- // senddata(table1[v_shi]);
- // senddata('-');
- // senddata(table1[key_flag]);
- // senddata(0x0d);
- // senddata(0x0a);
-
-
- }
- }
- /**********************************************************/
- void interrupt_uart() interrupt 4
- {
-
- ES=0; //關串口中斷
-
- table[i]=SBUF;//命令存到命令數組
- if(table[0]=='W')
- i++;
- else
- i=0;
- RI=0; //軟件清除接收中斷
- ES=1;//開串口中斷
- if(i>8) //如果接受字節(jié)大于8個開始檢測接受字節(jié)后六位數據 Work_v_ad
- {
- if(table[5]=='v'&&table[6]=='_'&&table[7]=='a'&&table[8]=='d')
- {
- volt=((AD_get(0)*2.5)/AD_get(7))*2*1000;
- v_shi=volt/1000;
- v_ge=volt%1000/100;
- v_xiao1=volt%100/10;
- v_xiao2=volt%10;
-
- senddata(table1[v_shi]);
- senddata('.');
- senddata(table1[v_ge]);
- senddata(table1[v_xiao1]);
- senddata(table1[v_xiao2]);
-
- aolt=(AD_get(2)*0.002)*1000;
- a_shi=aolt/1000;
- a_ge=aolt%1000/100;
- a_xiao1=aolt%100/10;
- a_xiao2=aolt%10;
-
- senddata('_');
- if(a_shi>0)
- senddata(table1[a_shi]);
- senddata(table1[a_ge]);
- senddata(table1[a_xiao1]);
- senddata(table1[a_xiao2]);
- senddata(0x0d);
- senddata(0x0a);
- com_flag=1;
-
- }
- if(table[5]=='v'&&table[6]=='_'&&table[7]=='a'&&table[8]=='a')
- {
- aolt=(AD_get(2)*0.002)*1000;
- a_shi=aolt/1000;
- a_ge=aolt%1000/100;
- a_xiao1=aolt%100/10;
- a_xiao2=aolt%10;
-
- senddata(table1[a_shi]);
- //senddata('.');
- senddata(table1[a_ge]);
- senddata(table1[a_xiao1]);
- senddata(table1[a_xiao2]);
- senddata(0x0d);
- senddata(0x0a);
- com_flag=1;
-
- }
- if(table[5]=='v'&&table[6]=='_'&&table[7]=='c'&&table[8]=='d')
- {
- com_flag=1;
- v_fd=1;
- v_cd=0;
- }
-
- if(table[5]=='v'&&table[6]=='_'&&table[7]=='f'&&table[8]=='d')
- {
- com_flag=1;
- v_cd=1;
- v_fd=0;
- }
-
- if(table[5]=='v'&&table[6]=='o'&&table[7]=='f'&&table[8]=='f')
- {
- com_flag=1;
- v_cd=1;
- v_fd=1;
-
- }
- i=0;
- }
-
- }
- void T0_time() interrupt 1
- {
- TH0=(65536-45872)/256;
- TL0=(65536-45872)%256;
- num2++;
- if(num2==20)
- {
- num2=0;
- shan_flag=~shan_flag;
- lcd_flag=1;
- }
-
- if(time_flag==1)
- {
- num1++;
- if(num1==1200)
- {
- num1=0;
- time++;
- if(time==1000)
- time=0;
- mah=(AD_get(2)*0.002)*1000*time/60;
-
- }
- }
-
-
- }
復制代碼
程序寫的比較爛,大家參考一下吧
|