📄 main.c
字号:
// Target : STC12C5A60S2
// Crystal: 11.0592Mhz
#include <reg52.h>
#include "fun.h"
//声明
void init_devices(void);
void port_init(void)
{
//设置P3.2~P3.4为输入,P3.5~P3.7为开漏输出
P3M1 = 0xfc; //1111 1100
P3M0 = 0xe0; //1110 0000
//设置P2.0为开漏输出
P2M1=0X01;
P2M0=0X01;
d_vote = 1; //关闭投票指示灯
//关闭d1 d2 d3 ,按键s1 s2 s3为高电平
P3 = 0xff;
//设置P1.4为推挽输出,P1.0、P1.7为高阻输入(AD转换用)
P1M1 = 0x81; //1000 0001
P1M0 = 0x10; //0001 0000
m_power = 0; //打开无线模块电源
}
//Watchdog initialize
//约568.8ms
void watchdog_init(void)
{
WDT_CONTR = 0x33;//启动定时器,11.0592MHz晶振下,溢出时间568.8ms
}
//外部中断0
void INT0_interrupt() interrupt 0
{
//external interupt on INT0
//关外部中断0、外部中断1
IE &= 0xfa; //1111 1010
m_power = 0; //打开无线模块电源
d_vote = 1; //关闭投票指示灯
P3 |= 0xe0; //关闭d1 d2 d3
d3 = 0; //点亮d3
msdelay(500);
WDR(); //喂狗
d2 = 0; //点亮d2
msdelay(500);
WDR();
d1 = 0; //点亮d1
msdelay(500);
WDR();
d_vote = 0; //点亮 d_vote
msdelay(500);
WDR();
init_devices();
m_power = 0; //打开无线模块电源
d_vote = 1; //关闭投票指示灯
P3 |= 0xe0; //关闭d1 d2 d3
}
//外部中断1
void INT1_interrupt() interrupt 2
{
//external interupt on INT1
//关外部中断0、外部中断1
IE &= 0xfa; //111 1010
m_power = 0; //打开无线模块电源
//LED从下到上依次点亮
d_vote = 1; //关闭投票指示灯
P3 |= 0xe0; //关闭d1 d2 d3
d3 = 0; //点亮d3
msdelay(500);
WDR(); //喂狗
d2 = 0; //点亮d2
msdelay(500);
WDR();
d1 = 0; //点亮d1
msdelay(500);
WDR();
d_vote = 0; //点亮 d_vote
msdelay(500);
WDR();
init_devices();
m_power = 0; //打开无线模块电源
d_vote = 1; //关闭投票指示灯
P3 |= 0xe0; //关闭d1 d2 d3
}
//TIMER0 initialize
// desired value: 16mSec
// actual value: 16mSec
void timer0_init()
{
AUXR &=0x7F; //T0x12 = 0,定时器0使用12分频
TMOD |= 0X01;
TH0 = T0_16ms >> 8;
TL0 = T0_16ms,
ET0 = 1; //允许T0中断
}
//定时器0中断 ,16ms一次
void Timer0_interrupt() interrupt 1
{
//重装初值
TH0 = T0_16ms >> 8; //TH0 = T0_16ms / 256 = 0xc6
TL0 = T0_16ms; //TL0 = T0_16ms % 256 = 0x66
cnt++;
if (cnt==me) //轮到自己发
{
if (addr!=0)//地址没有问题,可以发送
{
TR0 = 0; //关定时器
REN = 0; //禁止接收数据
putchar(sent[0]);
putchar(sent[1]);
putchar(sent[2]);
REN = 1; //允许接收数据
}
else
{
TR0 = 0; //关定时器
REN = 1; //允许接收数据
}
}
}
//TIMER2 initialize
// desired value: 50mSec
// actual value: 50.000mSec (0.0%)
void timer1_init()
{
AUXR &=0xbF; //T1x12 = 0,定时器1使用12分频
TMOD |= 0X10; //定时器1模式1,16bit
TH1 = T1_50ms >> 8;
TL1 = T1_50ms;
ET1 = 1; //允许T1中断
}
//定时器1中断 ,50ms一次
void Timer1_interrupt() interrupt 3
{
//重装初值
TH1 = T1_50ms >> 8;
TL1 = T1_50ms;
time++; //按键计时
time_f++; //空闲计时
if (time==10) //按键之后500ms
{
//关按键灯
P3 |= 0xe0; //关d1 d2 d3
}
if (time==40)//按键之后2S
{
key1=0; //进入工厂模式步骤清零
}
if (time_f==10) //500ms未接收到数据
{
recnum=0; //接收数据清零
}
if (time_f==1200) //1分钟未接收到数据 没有按键
{
sleep(); //休眠 power down
}
}
//UART0 initialize
// desired baud rate: 9600
// char size: 8 bit
// parity: Disabled
void uart0_init(void)
{
//BRTR=1允许BRT BRTx12=1 S1BRS = 1使用BRT
AUXR |=0x15; //0001 0101
//方式1,8 N 1,允许接收
SCON = 0x50; //SM0 = 0,SM1=1,REN=1;
//11.0592MHz,9600
BRT = 256 - (fosc/32/9600); //BRT = 0xdc
ES = 1; //允许串口中断
}
//串口中断
void USART_interrupt() interrupt 4
{
//uart has received a character in SBUF
unsigned int i;
//如果是接收中断
if (RI)
{
RI=0; //清接收中断
time_f=0; //空闲时间计数器清零
disable(); //关闭定时器0、定时器1、ADC转换
//防止缓冲区数组溢出错误
if (recnum < 5)
{
rec[recnum]=SBUF;
recnum++; //接收计数指针+1
loop: //开始处理流程
if (recnum>2) //至少收了3个数据
{
if ((rec[0]&0x0c)==0x00 && ((rec[0]&0x80)==0x00)) //包头正确 上位机下发的
{
//计算校验
checkXOR=rec[0] ^ rec[1];
if ((checkXOR==rec[2])) //校验正确
{
recieve(); //当作协议处理
recnum=0; //接收清零
goto loop1; //跳走
}
else //校验不正确
{
//缓冲区整体前移
for (i=1;i<recnum;i++)
{
rec[i-1]=rec[i];
}
recnum--;
if (recnum<=0) //接收缓冲区没有数据了
{
//计数器清零,开中断返回
recnum=0;
goto loop1;
}
else //接收缓冲区还有数据
{
goto loop; //跳回去再检查
}
}
}
else //不是包头
{
//缓冲区整体前移
for (i=1;i<recnum;i++)
{
rec[i-1]=rec[i];
}
recnum--;
if (recnum<=0) //接收缓冲区没有数据了
{
//计数器清零,开中断返回
recnum=0;
goto loop1; //跳走
}
else //接收缓冲区还有数据
{
goto loop; //跳回去再检查
}
}
}
else //<=2
{
//什么也不做,开中断返回主程序,等待接收下一个数据
}
}
else //如果recnum >=5,缓冲区溢出
{
recnum = 0; //全部清空
// 开中断返回主程序,等待接收下一个数据
}
loop1: //结束处理流程
enable(); //开中断返回
}
//如果是发送中断
if (TI)
{
TI = 0; //清除发送中断
}
}
//ADC initialize
// Conversion time: 48uS
void adc_init(void)
{
P1ASF = 0x00; //P1.0用作AD转换
//转换结果清零
ADC_RES = 0;
ADC_RESL = 0;
//ADC_POWER=1,SPEED1=0,SPEED0=0,
//ADC_FLAG=0,ADC_START=0,CHS2/CHS1/CHS0=000
//11.0592MHz,540个时钟周期转换一次,速度约125KHz,时间约 48us
ADC_CONTR = 0X80;
//等待4周期
_nop_();
_nop_();
_nop_();
_nop_();
//ADRJ = 0,ADC_RES寄存器保存10位A/D转换结果的高8位,ADC_RESL保存结果的低2位
AUXR1 &= 0xfb;
}
//AD转换中断
void ADC_interrupt() interrupt 5
{
ADC_CONTR &= 0Xef; //ADC_FLAG清零
//计算电压值
ad_result10 = ADC_RES;
ad_result10 = ( ad_result10 << 2 ) | ADC_RESL;
f_adconverting = 0;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
char i=0;
//stop errant interrupts until set up
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
EA = 0; //disable all interrupts
port_init();
watchdog_init(); //设置且启动看门狗
timer0_init();
timer1_init();
uart0_init();
adc_init();
PCON &= 0xfd; //关闭power down模式,PD位置0
//all peripherals are now initialized
//按键清零
ty=0;
qq=0;
fd=0;
key0=0;
key1=0;
//时间、计数清零
time=0;
time_m=0;
time_f=0;
cnt=0;
//状态清零
f_start=0;
f_sleep=0;
f_volt=0;
f_adconverting = 0;
readset();//读取本机地址
me=addr;
WDR(); //喂狗
//刚上电,AD不准,多检查一次
checkpower(); //检查电源
WDR();
checkpower();
WDR();
if (vin<1.75) //如果需要充电
{
//灯全关
d_vote = 1;
P3 |= 0xe0;
for (i=0;i<5;i++)
{ //闪烁5次d_vote
d_vote=0; //亮d_vote
msdelay(500);
WDR();
d_vote=1; //灭d_vote
msdelay(500);
WDR(); //喂狗
}
}
}
void main(void)
{
int i;
init_devices();
//insert your functional code here...
EA = 1; //开总中断
while(1)
{
//关INT0 INT1中断
IE &= 0xfa; //111 1010
WDR();
if (recnum>5) //任意时刻接收计数器大于5,清零
{
recnum=0;
}
if (f_sleep==1) //休眠标
{
msdelay(10);
f_start=0;
f_sleep=0;
sleep(); //休眠power down
}
if (f_volt==1) //低电提示
{
f_volt=0;
//灯全关
d_vote = 1;
P3 |= 0xe0;
for (i=0;i<5;i++)
{
//闪烁5次d_vote
d_vote=0; //亮d_vote
msdelay(500);
WDR();
d_vote=1; //灭d_vote
msdelay(500);
WDR(); //喂狗
}
}
//---------------------------------------------------
if (s1==0) //按键S1 P3.4 同意
{
ty++;
time_f=0;
msdelay(10);
if ((s1==0) && (ty==1))
{
offled(1); //点亮D1,关闭D2、D3
time=0;
if (f_start==1) //如果是投票状态
{
key0=1;
}
key1++; //按键次数加1
if(key1>3)
{
key1=0; //按三次
}
}
}
else
{
ty=0;
}
//----------------------------------------------------
if ((s2==0)&(s1=1))//s2按下,s1未按,key0=3
{
qq++;
time_f=0;
msdelay(10);
if ((s2==0)&(s1=1) & (qq==1))
{
offled(2);//点亮D2,关闭D1、D3
time=0;
if (f_start==1) key0=3;
if ((key1>2)&(key1<5))
{
key1++; //同意按三次后弃权按过2次
}
else key1=0;
}
}
else
{
qq=0;
}
//--------------------------------------------------------
if (s3==0) //s3按下,key0=2
{
fd++;
time_f=0;
msdelay(10);
if ((s3==0) && (fd==1))
{
offled(3); //点亮D3,关闭D2、D1
if (f_start==1) key0=2;
time=0;
d3=1; //关d3
if ((key1>4)&(key1<8))
{
key1++; //之后反对按3下
}
else key1=0;
}
if(key1==8) //按第3下反对 一整套进入工厂模式动作做完
{
REN=1; //允许串口接收
key1=0;
//offled(1);
key0=12; //key0=12,编地址状态
}
}
else
{
fd=0;
}
//-------------------------------------------------
if(key0==12) //工厂模式
{
//从下往上循环亮灯
//灯全关
d_vote = 1;
P3 |= 0xe0;
d3=0; //开d3
msdelay(500);
WDR();
d3=1; //关d3
d2=0;
msdelay(500);
WDR(); //喂狗
d2=1;
d1=0;
msdelay(500);
WDR();
d1=1;
d_vote=0;
msdelay(500);
WDR(); //喂狗
d_vote=1;
time_m++;
}
if ((key0==12) && (time_m>5)) //循环超过5次
{
key0=0;
time_m=0;
//灯全关
d_vote = 1;
P3 |= 0xe0;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -