赞
踩
感受:难,比起第8 ,第9,第11套决赛来说,出题人无所不用其极。它也得到了我的尊重,我特地写篇文章总结总结。
(1)功能要求较多:
代码比其他的赛题要多,细节也更多,刚开始写怀疑按键和串口会冲突,试着用一个锁去调度公用的P30和P31资源,结果根本不需要,因为按键只用到了13,12,16,17,刚好避开了P30和P31,所以按键的动态扫描只针对这四列就行。
(2)资源占用多
(3)对外设的细节把握较多
解题步骤:
数码管动态刷新
按键动态扫描(只扫描按键所需的4行,就屏蔽了P30和P31)
led动态刷新
按键长按短按判断(状态机实现)
外设定时使用(超声波,温度,epprom)
串口消息收发(状态机加串口中断)
全工程如下
main函数如下
-
-
- #include "sys.h"
-
-
- u8 s=0;
- u8 keytime=0;
- u8 smgtime=0;
-
- u16 temp;//温度
- u8 ctemp=30;//温度参数
- u8 dis=0;//距离
- u8 cdis=35;//距离参数
- u16 cge=0;//参数变动次数
- u8 cmode=1;//参数编号 1 :温度数据 2:距离数据
- // 3:温度参数 4:距离参数 5:变更次数
- u16 tempt=0;//读取温度间隔时间
- bit uic=0;
- u16 dist=0;//读取距离间隔时间
-
-
- u8 longf=0;
- u16 longt=0;
- bit cdac=0; // 0:dac输出 1:dac关闭
- u8 ledflush=0;
- u16 dact=0;//dac输出时间
- u8 savef=0;//参数变更保存到epprom标志
-
-
-
- u8 bstate=0;//串口指令状态
- u8 xdata sendbuf[18]={'\0'};
-
- //dac电压输出
- void DacOut(){
-
- if(cdac){
- Pcf_W_Dac(20);
- }
- else{
- if(dis<=cdis) Pcf_W_Dac(102);
- else
- Pcf_W_Dac(204);
- }
- }
- //判断LED的状态
- void Judgement(){
-
- if(temp<(ctemp*100))LEDDT[0]=0;
- else LEDDT[0]=1;
- if(dis<cdis)LEDDT[1]=2;
- else LEDDT[1]=0;
- if(!cdac)LEDDT[2]=3;
- else LEDDT[2]=0;
-
-
- }
- //判断按键长按与短按状态
- void los(){
- static int keys=0;
- if(key_v==12)keys=12;
- else if(key_v==13)keys=13;
-
- if(!keys)return;
- switch(longf){
- case 0:
- longt=0;
- if(key_v==keys)longf=1;
- break;
- case 1:
- if(key_v==keys){
- if(longt++>1000){//达到长按临界值执行长按的瞬间性操作
- if(keys==12)cge=0;//长按12清0
- else if(keys==13)cdac=~cdac;
- longf=2;
- }
- }
- //按键松开
- else {
- if(longt<=1000){ //执行短按
- if(keys==12){
- if(!uic){//数据界面显示
- if(cmode==1)cmode=2;
- else if(cmode==2)cmode=5;
- else cmode=1;
- }
- else {//参数界面切换
- if(cmode==3)cmode=4;
- else cmode=3;
- }
- }
- else if(keys==13){
- if(!uic){
- uic=1;
- cmode=3;
- }
- else {
- uic=0;
- cmode=1;
- }
- }
- keys=0;
- longf=0;
- }
- }
- break;
-
- case 2:
- if(key_v==keys){//执行长按的连续性操作
- //没有操作空
- }
- else {
- longf=0;
- keys=0;
- }
- break;
- }
- }
-
-
-
-
- void UISetting(){
-
- if(cmode==1){//温度数据显示
- DT[0]=21;
- DT[1]=10;
- DT[2]=10;
- DT[3]=10;
- DT[4]=temp/1000%10;
- DT[5]=temp/100%10+11;
- DT[6]=temp/10%10;
- DT[7]=temp%10;
-
- }
- else if(cmode==2){//距离数据显示
- DT[0]=22;
- DT[1]=10;
- DT[2]=10;
- DT[3]=10;
- DT[4]=10;
- DT[5]=10;
- DT[6]=dis/10%10;
- DT[7]=dis%10;
- }
- else if(cmode==3){//温度参数显示
- DT[0]=24;
- DT[1]=10;
- DT[2]=10;
- DT[3]=1;
- DT[4]=10;
- DT[5]=10;
- DT[6]=ctemp/10%10;
- DT[7]=ctemp%10;
- }
- else if(cmode==4){//距离参数显示
- DT[0]=24;
- DT[1]=10;
- DT[2]=10;
- DT[3]=2;
- DT[4]=10;
- DT[5]=10;
- DT[6]=cdis/10%10;
- DT[7]=cdis%10;
- }
- else {//变更次数显示
-
-
-
- DT[0]=23;
- DT[1]=10;
- DT[2]=10;
- DT[3]=cge>=10000?cge/10000:10;
- DT[4]=cge>=1000?cge/1000%10:10;
- DT[5]=cge>=100?cge/100%10:10;
- DT[6]=cge>=10?cge/10%10:10;
- DT[7]=cge%10;
-
- }
-
- }
-
- void KeyConsole(){
-
- if(keytime>8){
- keytime=0;
-
- key_scan();
-
- if(rkey){
- switch(rkey){
-
- case 16:
- //参数次数变动
- if(cmode==3){
-
-
- cge++;
- if(ctemp==0)return;
- ctemp-=2;
- }
- else if(cmode==4){
- cge++;
- if(cdis==0)return;
- cdis-=5;
- }
- savef=1;
-
- break;
- case 17:
-
- if(cmode==3){
- ctemp+=2;
- cge++;
- }
- else if(cmode==4){
- cdis+=5;
- cge++;
- }
- savef=1;
- break;
- default:
- break;
- }
- }
-
- }
-
-
- }
- void main(){
-
- UartInit();//定时器2的串口初始化
- Timer1Init();
- sys_init();
- Timer0Init();
-
-
- while(1){
- //按键扫描
- KeyConsole();
- //界面显示
- if(smgtime>48){
- smgtime=0;
-
- UISetting();
- Judgement();
- if(savef){
- if(savef==1){//将改变次数保存到epprom ,分两次保存
- EppromW(0,cge/256);
- savef=2;
- }
- else if(savef==2){
- EppromW(1,cge%256);
- savef=0;
- }
- }
- }
- if(dact>479){
- dact=0;
- DacOut();
- }
- //测温
- if(tempt>540){
- //
- tempt=0;
- temp=ReadTemp()*100;
-
- }
- //超声波测距
- if(dist>=898){
- dist=0;
- dis=get_dis();
-
- }
-
-
-
- }
-
- }
- void TIME1() interrupt 3{//
-
- smg_play(DT[s],s++);
- if(s>7)s=0;
- smgtime++;
- keytime++;
- dist++;
- tempt++;
- dact++;
- los();
- if(ledflush++==10){
- ledflush=0;
- LedRunning();
- }
-
-
- }
-
-
-
- void UART1() interrupt 4{
-
-
- ReceiveDate();
-
-
-
- }
-
-
- void ReceiveDate(){
- u8 rec;
-
- if(RI==1){ //每次接受完字符后判断
- RI=0;
- rec=SBUF;
- switch(bstate){
- case 0:
- if(rec=='S')bstate=1;
- else if(rec=='P')bstate=5;
- else bstate=13;
- break;
- case 1:
- if(rec=='T')bstate=2;
- else bstate=13;
- break;
- case 2:
- if(rec=='\r')bstate=3;
- else bstate=13;
- break;
- case 3:
- if(rec=='\n')bstate=4;
- else bstate=13;
- break;
- case 5:
- if(rec=='A')bstate=6;
- else bstate=13;
- break;
- case 6:
- if(rec=='R')bstate=7;
- else bstate=13;
- break;
- case 7:
- if(rec=='A')bstate=8;
- else bstate=13;
- break;
- case 8:
- if(rec=='\r')bstate=9;
- else bstate=13;
- break;
- case 9:
- if(rec=='\n')bstate=10;
- else bstate=13;
- break;
-
- }
-
-
-
-
- if(bstate==4){//查询数据指令
- sendbuf[0]='$';
- sendbuf[1]=dis/10%10+48;
- sendbuf[2]=dis%10+48;
- sendbuf[3]=',';
- sendbuf[4]=temp/1000%10+48;
- sendbuf[5]=temp/100%10+48;
- sendbuf[6]='.';
- sendbuf[7]=temp/10%10+48;
- sendbuf[8]=temp%10+48;
- sendbuf[9]='\r';
- sendbuf[10]='\n';
- sendbuf[11]='\0';
- SendString(sendbuf);
- bstate=0;
-
- }
- //查询参数指令
- //返回当前的距离参数和温度参数
- else if(bstate==10){
- sendbuf[0]='#';
- sendbuf[1]=cdis/10%10+48;
- sendbuf[2]=cdis%10+48;
- sendbuf[3]=',';
- sendbuf[4]=ctemp/10%10+48;
- sendbuf[5]=ctemp%10+48;
- sendbuf[6]='\r';
- sendbuf[7]='\n';
- sendbuf[8]='\0';
- SendString(sendbuf);
- bstate=0;
-
- }
- if(bstate==13){
- bstate=0;
- //发送错误
- SendString("ERROR\r\n");
- }
-
-
- }
- }
sys.c
-
- #include "sys.h"
-
- u8 key_state=0;
- u8 rkey=0;
- u8 key_v=0;
-
- u8 DT[]={10,10,10,10,10,10,10,10};
- u8 code SMGINDEX[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,
- 0xc0&0x7f,0xf9&0x7f,0xa4&0x7f,0xb0&0x7f,0x99&0x7f,0x92&0x7f,
- 0x82&0x7f,0xf8&0x7f,0x80&0x7f,0x90&0x7f,
- 0xc6,0xc7,0xc8,0x8c //C L n p
-
-
- };
-
-
-
- u8 code LED[]={0xff,0xfe,0xfd,0xfb};
- u8 LEDDT[]={0,0,0};
- void LedRunning(){
-
- P0=0xff;
- P0=LED[LEDDT[0]]&LED[LEDDT[1]]&LED[LEDDT[2]];
- lock(4);
-
- }
-
- void sys_init(){
-
- P0=0xff;
- lock(4);
-
-
- P0=0;
- lock(5);
-
-
- P0=0;
- lock(6);
-
-
- P0=0xff;
- lock(7);
-
-
-
- }
- void smg_play(u8 du,u8 we){
-
-
-
- P0=0xff;
- lock(7); //消影
-
- P0=0;
- P0=1<<we;
- lock(6);
-
- P0=0xff;
- P0=SMGINDEX[du];
- lock(7);
-
-
- }
- void key_scan(){
-
-
- switch(key_state){
- case 0:
- key_v=0;
- P32=1;
- P33=1;
- P34=0;
- P35=0;
-
- if(P33!=1||P32!=1)key_state=1;
- break;
-
-
- case 1:
- P32=1;
- P33=1;
- P34=0;
- P35=0;
- if(P32!=1||P33!=1){
-
- if(!P32)key_v=5;
- else if(!P33)key_v=4;
-
- P34=1;
- P35=1;
- P32=0;
- P33=0;
- if(!P34)key_v+=12;
- else if(!P35)key_v+=8;
- rkey=key_v;
- key_state=2;
-
- }
- else
- key_state=0;
- break;
-
-
- case 2:
- P32=1;
- P33=1;
- P34=0;
- P35=0;
- rkey=0;
- if(P32==1&&P33==1)key_state=0;
- break;
- default:
- break;
- }
- }
-
- void Timer1Init(void) //1毫秒@12.000MHz
- {
- AUXR &= 0xBF; //定时器时钟12T模式
- TMOD &= 0x0F; //设置定时器模式
- TL1 = 0x18; //设置定时初始值
- TH1 = 0xFC; //设置定时初始值
- TF1 = 0; //清除TF1标志
- TR1 = 1; //定时器1开始计时
- EA=1;
- ET1=1;
- }
-
-
-
-
-
-
-
-
sys.h
- #ifndef __SYS_H_
- #define __SYS_H_
-
- #include "mystc.h"
- #define lock(x) P2=P2&0x1f|(x<<5); P2=P2&0x1f;
-
-
- typedef unsigned char u8;
- typedef unsigned int u16;
- void sys_init();
- void smg_play(u8 du,u8 we);
- void key_scan();
-
- void Timer1Init(void);
- float ReadTemp();
- u16 get_dis();
- void Timer0Init(void);
- void LedRunning();
- void Pcf_W_Dac(u8 dat);
- void EppromW(u8 word,u8 dat);
- void SendString(u8 *str);
- void Send_char(u8 q);//发送单个字符
- void UartInit(void);
- u8 DT[];
- void ReceiveDate();
- u8 LEDDT[];
- extern u8 rkey;
- extern u8 key_v;
-
-
- #endif
其他的是外设驱动文件,需要用的函数都在sys.h里进行声明就行
onewire.c
- /*
- 程序说明: 单总线驱动程序
- 软件环境: Keil uVision 4.10
- 硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
- 日 期: 2011-8-9
- */
- #include "sys.h"
-
- sbit DQ = P1^4; //单总线接口
-
- //单总线延时函数
- void Delay_OneWire(unsigned int t) //STC89C52RC
- {
-
- u8 i=0;
- while(t--){
- for(i=0;i<10;i++);
- }
- }
-
- //通过单总线向DS18B20写一个字节
- void Write_DS18B20(unsigned char dat)
- {
- unsigned char i;
- for(i=0;i<8;i++)
- {
- DQ = 0;
- DQ = dat&0x01;
- Delay_OneWire(5);
- DQ = 1;
- dat >>= 1;
- }
- Delay_OneWire(5);
- }
-
- //从DS18B20读取一个字节
- unsigned char Read_DS18B20(void)
- {
- unsigned char i;
- unsigned char dat;
-
- for(i=0;i<8;i++)
- {
- DQ = 0;
- dat >>= 1;
- DQ = 1;
- if(DQ)
- {
- dat |= 0x80;
- }
- Delay_OneWire(5);
- }
- return dat;
- }
-
- //DS18B20设备初始化
- bit init_ds18b20(void)
- {
- bit initflag = 0;
-
- DQ = 1;
- Delay_OneWire(12);
- DQ = 0;
- Delay_OneWire(80);
- DQ = 1;
- Delay_OneWire(10);
- initflag = DQ;
- Delay_OneWire(5);
-
- return initflag;
- }
-
- float ReadTemp(){
-
- u8 low,high;
- u16 temp=0;
-
- init_ds18b20();
- Write_DS18B20(0xcc);
- Write_DS18B20(0x44);
-
- init_ds18b20();
- Write_DS18B20(0xcc);
- Write_DS18B20(0xbe);
-
- low=Read_DS18B20();
- high=Read_DS18B20();
- temp=high<<8|low;
-
- return temp*0.0625;
-
- }
-
-
-
-
-
sonnic.c(用定时器1进行定时算超声波距离)
- #include "sys.h"
- #include "intrins.h"
- //用定时器0来计算时间
-
- sbit RX=P1^1;
- sbit TX=P1^0;
- void Delay12us() //@12.000MHz
- {
- unsigned char i;
-
- _nop_();
- _nop_();
- i = 33;
- while (--i);
- }
-
-
- void Timer0Init(void) //100微秒@12.000HZ 定时器0做超声波计时器
- {
- AUXR &= 0x7F; //定时器时钟12T模式
- TMOD &= 0xF0; //设置定时器模式
- TL0 = 0x00; //设置定时初始值
- TH0 = 0x00; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 0; //定时器0开始计时
-
- }
-
- void csb_start(){
-
- u8 i=8;
- EA=0;
- while(i--){
- TX=1;
- Delay12us();
- TX=0;
- Delay12us();
- }
- EA=1;
-
- }
- u16 get_dis(){
- u16 dis;
- RX=1;
- csb_start();
- TR0=1;
- while(RX==1&&TF0==0);
-
- TR0=0;
- if(!TF0){
-
- dis=TH0<<8|TL0;
- dis=dis*0.017;
- if(dis<=2||dis>=400)dis=999;
- }
- else {
- dis=999;
- }
-
- TH0=TL0=0;
-
-
- return dis;
- }
-
-
-
-
iic.c
- /*
- 程序说明: IIC总线驱动程序
- 软件环境: Keil uVision 4.10
- 硬件环境: CT107单片机综合实训平台 8051,12MHz
- 日 期: 2011-8-9
- */
-
- #include "sys.h"
- #include "intrins.h"
-
- #define DELAY_TIME 5
-
- #define SlaveAddrW 0xA0
- #define SlaveAddrR 0xA1
-
- //总线引脚定义
- sbit SDA = P2^1; /* 数据线 */
- sbit SCL = P2^0; /* 时钟线 */
-
- void IIC_Delay(unsigned char i)
- {
- do{_nop_();}
- while(i--);
- }
- //总线启动条件
- void IIC_Start(void)
- {
- SDA = 1;
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- SDA = 0;
- IIC_Delay(DELAY_TIME);
- SCL = 0;
- }
-
- //总线停止条件
- void IIC_Stop(void)
- {
- SDA = 0;
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- SDA = 1;
- IIC_Delay(DELAY_TIME);
- }
-
- //发送应答
- void IIC_SendAck(bit ackbit)
- {
- SCL = 0;
- SDA = ackbit; // 0:应答,1:非应答
- IIC_Delay(DELAY_TIME);
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- SCL = 0;
- SDA = 1;
- IIC_Delay(DELAY_TIME);
- }
-
- //等待应答
- bit IIC_WaitAck(void)
- {
- bit ackbit;
-
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- ackbit = SDA;
- SCL = 0;
- IIC_Delay(DELAY_TIME);
- return ackbit;
- }
-
- //通过I2C总线发送数据
- void IIC_SendByte(unsigned char byt)
- {
- unsigned char i;
-
- for(i=0; i<8; i++)
- {
- SCL = 0;
- IIC_Delay(DELAY_TIME);
- if(byt & 0x80) SDA = 1;
- else SDA = 0;
- IIC_Delay(DELAY_TIME);
- SCL = 1;
- byt <<= 1;
- IIC_Delay(DELAY_TIME);
- }
- SCL = 0;
- }
-
- //从I2C总线上接收数据
- unsigned char IIC_RecByte(void)
- {
- unsigned char i, da;
- for(i=0; i<8; i++)
- {
- SCL = 1;
- IIC_Delay(DELAY_TIME);
- da <<= 1;
- if(SDA) da |= 1;
- SCL = 0;
- IIC_Delay(DELAY_TIME);
- }
- return da;
- }
- void EppromW(u8 word,u8 dat){
-
- IIC_Start();
- IIC_SendByte(0xa0);
- IIC_WaitAck();
- IIC_SendByte(word);
- IIC_WaitAck();
-
- IIC_SendByte(dat);
- IIC_WaitAck();
- IIC_SendAck(1);
- IIC_Stop();
-
-
- }
- void Pcf_W_Dac(u8 dat){
-
-
- IIC_Start();
- IIC_SendByte(0x90);
- IIC_WaitAck();
- IIC_SendByte(0x40);
- IIC_WaitAck();
-
- IIC_SendByte(dat);
- IIC_WaitAck();
- IIC_SendAck(1);
- IIC_Stop();
-
- }
uart.c
-
-
- #include "sys.h"
-
-
-
-
- void UartInit(void) //4800bps@12.000MHz
- {
- SCON = 0x50; //8位数据,可变波特率
- AUXR |= 0x01; //串口1选择定时器2为波特率发生器
- AUXR |= 0x04; //定时器时钟1T模式
- T2L = 0x8F; //设置定时初始值
- T2H = 0xFD; //设置定时初始值
- AUXR |= 0x10; //定时器2开始计时
- ES=1;
- }
-
-
-
-
- void Send_char(u8 q){
-
- ES=0;
- SBUF=q;
- while(!TI);
- TI=0;
- ES=1;
-
- }
- void SendString(u8 *str){
-
- while(*str!='\0'){
- Send_char(*str);
- str++;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。