|
地處北方,冬季車輛易虧電啟動困難,需要補充充電。利用手頭的老物件AT89C4051,ADC0832制作控制電路,IO口有限使用了PFC8574T驅動1602顯示。兩個工作模式,三段自動充電模式(充足自動轉為浮充)和定時充電模式(恒流充電)。制作完成才發現PCF8574T驅動1602顯示刷新太慢了影響響應速度,待充電主回路完成再聯調。
#include <reg51.h>
#include <intrins.h>
#define PCF_ADDR 0x4E //PCF8574T地址
unsigned char Data[3];
unsigned char Table[]="0123456789";
unsigned int delay_time;
long z=0;
unsigned char j;
unsigned char k;
unsigned char h;
unsigned char f;
unsigned char Set_A;
unsigned char Batt_V;
unsigned char Batt_A;
unsigned char JD=0;
unsigned char IS=0;
char hour=1;
char min=0;
char miao=59;
char count=0;
bit ptt=1;
sbit triac = P3^1; // 可控硅控制引腳
sbit ON_OFF = P3^7; //啟動停止開關
sbit MODE = P3^3; //模式
sbit JIA = P3^4; //加時間
sbit JIAN = P3^5; //減時間
sbit FMQ = P3^0; //蜂鳴器
sbit SCL = P1^1; // I2C時鐘線
sbit SDA = P1^0; // I2C數據線
sbit CS = P1^5;
sbit CLK = P1^6;
sbit DI0 = P1^7;
sbit WCS = P1^2;
sbit WCLK = P1^3;
sbit WDI0 = P1^4;
//----------函數聲明----------------------------
void process_3(unsigned int i,unsigned char *p) ;
void display(unsigned char *p);
void delay_us(unsigned int us);
void delay_ms(unsigned int ms);
void I2C_Start();
void I2C_Stop();
void I2C_WriteByte(unsigned char dat);
void PCF8574_Write(unsigned char dat);
void lcd_send_nibble(unsigned char nibble, unsigned char rs);
void lcd_send_byte(unsigned char dat, bit rs);
void lcd_init();
void lcd_set_cursor(unsigned char row, unsigned char col);
void lcd_write_string(char *str);
void init();
void display_SJ(unsigned char hour,unsigned char min);
unsigned char Current();
unsigned char V_SetA(bit CH);
//---------------------------------------------
unsigned char V_SetA(bit CH)//
{
unsigned char i,dat,dat2;
CS=0;
_nop_();
DI0=1;
CLK=1;
_nop_();
CLK=0;
_nop_();
DI0=1;
CLK=1;
_nop_();
CLK=0;
_nop_();
if(CH==0)//0通道/設置電流
{
DI0=0;
}
if(CH==1)//1通道/電壓
{
DI0=1;
}
CLK=1;
_nop_();
CLK=0;
DI0=1;
dat=0;
for(i=0;i<8;i++)
{
dat<<=1;
CLK=1;
_nop_();
CLK=0;
_nop_();
dat|=DI0;
}
dat2=0;
if(DI0==1)
dat2=0x80;
for(i=0;i<7;i++)
{
dat2>>=1;
CLK=1;
_nop_();
CLK=0;
_nop_();
if(DI0==1)
dat2|=0x80;
}
CS=1;
CLK=0;
DI0=1;
if(dat==dat2)
return(dat);
else
return 0;
}
//--------------------------
unsigned char Current()//0通道/電流
{
unsigned char i,dat,dat2;
WCS=0;
_nop_();
WDI0=1;
WCLK=1;
_nop_();
WCLK=0;
_nop_();
WDI0=1;
WCLK=1;
_nop_();
WCLK=0;
_nop_();
WDI0=0;//0通道/電流
WCLK=1;
_nop_();
WCLK=0;
WDI0=1;
dat=0;
for(i=0;i<8;i++)
{
dat<<=1;
WCLK=1;
_nop_();
WCLK=0;
_nop_();
dat|=WDI0;
}
dat2=0;
if(WDI0==1)
dat2=0x80;
for(i=0;i<7;i++)
{
dat2>>=1;
WCLK=1;
_nop_();
WCLK=0;
_nop_();
if(WDI0==1)
dat2|=0x80;
}
WCS=1;
WCLK=0;
WDI0=1;
if(dat==dat2)
return(dat);
else
return 0;
}
//---------------------------------------------
void process_3(unsigned int i,unsigned char *p)
{
p[0]=i/100%10;
p[1]=i/10%10;
p[2]=i%10;
}
//----------------------------
/*3位數顯示函數*/
void display(unsigned char *p)
{
unsigned char i;
for(i=0;i<3;i++)
{
if(i==2)
{
lcd_write_string(".");
}
lcd_send_byte(Table[p[i]], 1);
}
}
//------------------------------
void delay_us(unsigned int us) {
while (us--) {
_nop_();
_nop_();
_nop_();
_nop_();
}
}
//------------------------------
void delay_ms(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 114; j++);
}
//------------------------------
void I2C_Start() {
SDA = 1;
SCL = 1;
delay_us(5);
SDA = 0;
delay_us(5);
SCL = 0;
}
//-----------------
void I2C_Stop() {
SDA = 0;
SCL = 1;
delay_us(5);
SDA = 1;
delay_us(5);
}
//-------------------------------------
void I2C_WriteByte(unsigned char dat) {
unsigned char i;
for (i = 0; i < 8; i++) {
SDA = (dat & 0x80) ? 1 : 0;
dat <<= 1;
SCL = 1;
delay_us(5);
SCL = 0;
delay_us(5);
}
SDA = 1; // 釋放總線等待ACK
SCL = 1;
delay_us(5);
SCL = 0;
}
//------------------------------------
void PCF8574_Write(unsigned char dat) {
I2C_Start();
I2C_WriteByte(PCF_ADDR);
I2C_WriteByte(dat);
I2C_Stop();
}
//------------------------------------------------------------
void lcd_send_nibble(unsigned char nibble, unsigned char rs) {
unsigned char data_pcf;
// 數據位: P4-P7, RS: P0, E: P2, Backlight: P3 (開啟)
data_pcf = (nibble << 4) | (rs << 0) | (1 << 3);
// E下降沿
PCF8574_Write(data_pcf & ~(1 << 2)); // E=0
delay_us(1);
PCF8574_Write(data_pcf | (1 << 2)); // E=1
delay_us(1);
PCF8574_Write(data_pcf & ~(1 << 2)); // E=0
delay_us(100);
}
//---------------------------------------------
void lcd_send_byte(unsigned char dat, bit rs) {
lcd_send_nibble(dat >> 4, rs); // 高四位
lcd_send_nibble(dat & 0x0F, rs); // 低四位
}
//--------------------------
void lcd_init() {
delay_ms(50);
lcd_send_nibble(0x03, 0);
delay_ms(5);
lcd_send_nibble(0x03, 0);
delay_ms(1);
lcd_send_nibble(0x03, 0);
delay_us(100);
lcd_send_nibble(0x02, 0);
delay_us(100);
lcd_send_byte(0x28, 0); // 4位, 2行, 5x8
delay_us(100);
lcd_send_byte(0x0C, 0); // 顯示開, 光標關
delay_us(100);
lcd_send_byte(0x06, 0); // 增量不移屏
delay_us(100);
lcd_send_byte(0x01, 0); // 清屏
delay_ms(2);
}
//---------------------------------------------------------
void lcd_set_cursor(unsigned char col, unsigned char row) {
unsigned char address = (row == 0) ? 0x80 : 0xC0;
lcd_send_byte(address + col, 0);
}
//-----------------------------------
void lcd_write_string(char *str) {
while (*str) {
lcd_send_byte(*str++, 1);
}
}
//--------------------------
void display_SJ(unsigned char hour,unsigned char min)//時間顯示
{
unsigned int i;
unsigned char q[2];
unsigned char w[2];
q[0]=hour/10;
q[1]=hour%10;
w[0]=min/10;
w[1]=min%10;
lcd_send_byte(Table[q[0]],1);
lcd_send_byte(Table[q[1]],1);
if(ptt==1||ON_OFF==1)
{
lcd_set_cursor( 13, 0 );
lcd_write_string(":");//秒閃爍
}
else
{
lcd_write_string(" ");
}
lcd_send_byte(Table[w[0]],1);
lcd_send_byte(Table[w[1]],1);
if(hour==0&&min==0)//定時到
{
TR1=0;
TR0=0;
ET1=0;
ET0=0;
EX0=0;
EA=0;
triac = 1; // 關閉脈沖
for(i=0;i<400;i++)
{
FMQ=0;
delay_ms(120);
FMQ=1;
lcd_set_cursor( 13, 0 );
lcd_write_string(":");
j=V_SetA(0);//設置電流
Set_A=j*200./255;
k=V_SetA(1);//電壓
Batt_V=k*200./255;
h=Current();//電流
Batt_A=h*200./255;
lcd_set_cursor(4, 0);
process_3(Set_A,Data);
display(Data);//設置電流
lcd_set_cursor(0, 1);
process_3(Batt_V,Data);
display(Data);//電壓
lcd_set_cursor(11, 1);
process_3(Batt_A,Data);
display(Data);//電流
}
while(1)
{
j=V_SetA(0);//設置電流
Set_A=j*200./255;
k=V_SetA(1);//電壓
Batt_V=k*200./255;
h=Current();//電流
Batt_A=h*200./255;
lcd_set_cursor(4, 0);
process_3(Set_A,Data);
display(Data);//設置電流
lcd_set_cursor(0, 1);
process_3(Batt_V,Data);
display(Data);//電壓
lcd_set_cursor(11, 1);
process_3(Batt_A,Data);
display(Data);//電流
}
}
}
//-----------------------------------
void init() {
IT0 = 1; // INT0(P3.2)下降沿觸發模式
EX0 = 1; // 允許INT0中斷
TMOD=0x11;
ET0 = 1; // 允許定時器0中斷
TL1 = (65536-50000)%256;
TH1 = (65536-50000)/256;
ET1 = 1;
TF1 = 0;
EA = 0;
// EA = 1; // 開啟總中斷
}
/* 主函數 */
void main()
{
bit a=0;
bit b=0;
bit c=0;
bit x=0;
unsigned char i;
unsigned char t;
triac = 1; // 關閉脈沖
init();
lcd_init();
lcd_set_cursor(4, 0);
lcd_write_string("Hello!!!");
for(i=0;i<5;i++)
{
FMQ=0;
delay_ms(250);
FMQ=1;
delay_ms(250);
}
if(ON_OFF==0)//開關在啟動檔
{
lcd_send_byte(0x01, 0); // 清屏
while(1)
{
FMQ=0;
lcd_set_cursor(3, 0);
lcd_write_string("Error!!!");
}
}
for(i=0;i<5;i++)
{
delay_ms(20);
k=V_SetA(1);
}
Batt_V=k*200./255;
if(Batt_V==0)//電池沒接或反接
{
lcd_send_byte(0x01, 0); // 清屏
while(1)
{
FMQ=0;
lcd_set_cursor(3, 0);
lcd_write_string("Error!!!");
}
}
lcd_send_byte(0x01, 0); // 清屏
lcd_set_cursor(0, 0);
lcd_write_string("Set:");
lcd_set_cursor(8, 0);
lcd_write_string("A");//設置電流
lcd_set_cursor(4, 1);
lcd_write_string("V");//電壓
lcd_set_cursor(15, 1);
lcd_write_string("A");//電流
while(1)
{
lcd_set_cursor(4, 0);
process_3(Set_A,Data);
display(Data);//設置電流
lcd_set_cursor(0, 1);
process_3(Batt_V,Data);
display(Data);//電壓
lcd_set_cursor(11, 1);
process_3(Batt_A,Data);
display(Data);//電流
f=V_SetA(0);//設置電流
j=f;
if(JD==0)j=j;//第一階段恒流
if(JD==1)j=j/2;//第二階段恒流電流減半
if(JD==2);//第三階段恒壓
Set_A=j*200./255;
k=V_SetA(1);//電壓
Batt_V=k*300./255;
h=Current();//電流
Batt_A=h*200./255;
if(k==0)//電池開路
{
lcd_send_byte(0x01, 0); // 清屏
while(1)
{
TR0=0;
ET0=0;
EX0=0;
EA=0;
triac = 1; // 關閉脈沖
FMQ=0;
lcd_set_cursor(3, 0);
lcd_write_string("Error!!!");
}
}
if(Batt_A>=200)//20.0A過流
{
FMQ=0;
}
else
{
FMQ=1;
}
if(ON_OFF==0)//啟動
{
if(x==0)
{
FMQ=0;
delay_ms(250);
FMQ=1;
x=1;
}
EA=1;
if(IS==0)//非定時
{
if((Batt_V<138)&&a==0)//第一階段恒流
{
a=1;
JD=0;
}
if(((Batt_V>=138)&&(Batt_V<143))&&b==0)//第二階段恒流
{
b=1;
JD=1;
}
if((Batt_V>=143)&&c==0)//第三階段恒壓14.3V
{
c=1;
JD=2;
}
switch(JD)
{
case 0:
z=z+(j-h)*2;//第一階段恒流
if(z<100)z=100;
if(z>8160)z=8160;
delay_time=10000-z;
break;
case 1:
z=z+(j-h)*2;//第二階段恒流
if(z<100)z=100;
if(z>8160)z=8160;
delay_time=10000-z;
break;
case 2:
z=z+(k-183)*2;//第三階段恒壓14.3V
if(z<100)z=100;
if(z>8160)z=8160;
delay_time=10000-z;
t++;
if(t==10)FMQ=0;
if(t==11)FMQ=1;
if(t==120)t=0;
break;
default:
break;
}
}
else //定時
{
TR1=1;
z=z+(f-h)*2;//恒流
if(z<100)z=100;
if(z>8160)z=8160;//255*32=8160
delay_time=10000-z;
// delay_time=10000-(f*32);
}
}
if(ON_OFF==1)//停止
{
t=0;
x=0;
EA=0;
triac = 1; // 關閉脈沖
if(IS==1)
{
TR1=0;
}
if(JIA==0)//定時加
{
FMQ=0;
delay_ms(100);
FMQ=1;
if(JIA==0)
{
hour++;
if(hour>99)
{
hour=99;
}
}
while(JIA==0);
}
if(JIAN==0)//定時減
{
FMQ=0;
delay_ms(100);
FMQ=1;
if(JIAN==0)
{
hour--;
if(hour<1)
{
hour=1;
}
}
while(JIAN==0);
}
if(MODE==0)//模式
{
FMQ=0;
delay_ms(100);
FMQ=1;
if(MODE==0)
{
IS++;
while(MODE==0);
if(IS>1)
{
IS=0;
}
}
}
}
if(IS==0)
{
lcd_set_cursor(11, 0);
lcd_write_string("--:--");
}
if(IS==1)
{
lcd_set_cursor(11, 0);
display_SJ(hour,min);//時間
}
}
}
/* INT0中斷服務函數 */
void int0_isr() interrupt 0
{
TR0 = 0; // 停止定時器0
// 計算定時器初值(12MHz晶振,1us計數)
TH0 = (65536 - delay_time) /256; // 高字節
TL0 = (65536 - delay_time) %256;// 低字節
TR0 = 1; // 啟動定時器0
}
/* 定時器0中斷服務函數 */
void timer0_isr() interrupt 1
{
static unsigned char i;
TR0 = 0; // 停止定時器0
triac = 0; // 觸發可控硅
// 短暫延時確保觸發(約10us,根據實際需求調整)
for(i = 0; i < 10; i++); // 粗略延時
triac = 1; // 關閉脈沖
}
/* 定時器1中斷服務函數 */
void timer1(void) interrupt 3
{
TL1 = 0xB0;
TH1 = 0x3C;
TF1 = 0;
count++;
if(count==20)
{
count=0;
miao--;
ptt=~ptt;
if(miao<0)
{
miao=59;
min--;
if(min<0)
{
min=59;
hour--;
if(hour<0)
{
hour=0;
}
}
}
}
}
|
評分
-
查看全部評分
|