遇到的问题:
- 矩阵键盘中的P34口和测频率的P34会冲突导致键盘不能正常使用。所以键盘使用到P34的时候注意是否已经拔掉了。
- 使用超声波测距时要用不自动重装的,如果初始化成了自动重装模式会测不准。
- DAC输出不能在中断里一直执行,否则测不了距离。应该放在while(1)
- UART串口接收数据的处理要放在主函数里,不能放在1ms中断。
- 串口通信\r\n的作用。
- 长按短按功能。
main.c
#include <STC15F2K60S2.H>
#include <intrins.h>
#include "iic.h"
#include "onewire.h"
code unsigned char Seg_Table[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char smg[8];
unsigned char pre1=30,pre2=35; //先前参数 用来对比是否改变了参数
unsigned char change_times=0; //参数变动次数
unsigned char pram_temp=30;//温度参数
unsigned char pram_dist=35;//距离参数
bit dac_state=1;
bit busy; //串口
unsigned char rx_buf[10];
unsigned char rx_cnt=0;
unsigned char te[2]={'S','T'};
typedef struct
{
unsigned char b1:1;
unsigned char b2:1;
unsigned char b3:1;
unsigned char b4:1;
unsigned char b5:1;
unsigned char b6:1;
unsigned char b7:1;
unsigned char b8:1;
}Bits;
typedef union
{
unsigned char Hex;
Bits B;
}HexToB;
HexToB led_ctrl;
void vDevice_Process(unsigned char p2dat,unsigned char p0dat)
{
P0 = p0dat;
P2 = (P2&0x1f)|p2dat;
P2 = P2&0x1f;
}
//-------定时器-----------
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初值
T2H = 0xD1; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04;
EA = 1;
}
void UartInit(void) //4800bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0x8F; //设定定时初值
TH1 = 0xFD; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
//-------温度传感器----------
unsigned int tempture;
unsigned char cnt_temp;
void vRead_temp()
{
if(cnt_temp>100)
{
cnt_temp=0;
tempture = vRead_18b20()*100;
}
}
//-------超声波测距--------
void vSend_wave()
{
unsigned char i,j;
for(i=0;i<8;i++)
{
P10 = 1;
for(j=0;j<25;j++)
_nop_();
P10 = 0;
for(j=0;j<25;j++)
_nop_();
}
}
unsigned char vRecive_wave()
{
unsigned char temp;
TL0=0;TH0=0;
vSend_wave();
TR0=1;
while((P11==1)&&(TF0==0));
TR0=0;
if(TF0==1)
{
TF0=0;
temp=99;
}
else
{
temp = ((TH0<<8)|TL0)*0.017;
if(temp>99)temp=99;
}
return temp;
}
unsigned char dist; //0-99
unsigned char cnt_dist;
void vGet_distance()
{
if(cnt_dist>=100)
{
cnt_dist=0;
dist = vRecive_wave();
}
}
//--------DAC输出-------------
unsigned char cnt_dac;
void vDAC_out()
{
if(cnt_dac>=10)
{
cnt_dac=0;
if(dac_state==1)//启动状态
{
if(dist>=pram_dist) vOut_V(102);
if(dist<pram_dist) vOut_V(204);
}
else //停止状态 固定0.4V
{
vOut_V(20);
}
}
}
//-------数码管-----------
//数码管操作
unsigned char mode1=0;
unsigned char mode2=1;
void vSmg_Process()
{
if(mode1==0)
{
if(mode2==0)
{
smg[0]=0xc6;
smg[1]=0xff;
smg[2]=0xff;
smg[3]=0xff;
smg[4]=Seg_Table[tempture/1000];
smg[5]=Seg_Table[tempture/100%10]&0x7f;
smg[6]=Seg_Table[tempture/10%10];
smg[7]=Seg_Table[tempture%10];
}
else if(mode2==1)
{
smg[0]=0xc7;
smg[1]=0xff;
smg[2]=0xff;
smg[3]=0xff;
smg[4]=0xff;
smg[5]=0xff;
smg[6]=Seg_Table[dist/10];
smg[7]=Seg_Table[dist%10];
}
else if(mode2==2)
{
smg[0]=0xc8;
smg[1]=0xff;
smg[2]=0xff;
smg[3]=0xff;
smg[4]=0xff;
smg[5]=0xff;
smg[6]=Seg_Table[change_times/10];
smg[7]=Seg_Table[change_times%10];
}
}
else if(mode1==1)
{
if(mode2==0)
{
smg[0]=0x8c;
smg[1]=0xff;
smg[2]=0xff;
smg[3]=Seg_Table[1];
smg[4]=0xff;
smg[5]=0xff;
smg[6]=Seg_Table[pre1/10];
smg[7]=Seg_Table[pre1%10];
}
else if(mode2==1)
{
smg[0]=0x8c;
smg[1]=0xff;
smg[2]=0xff;
smg[3]=Seg_Table[2];
smg[4]=0xff;
smg[5]=0xff;
smg[6]=Seg_Table[pre2/10];
smg[7]=Seg_Table[pre2%10];
}
}
}
//数码管显示
void vSmg_Show()
{
static unsigned char i;
vDevice_Process(0xc0,0x00);
vDevice_Process(0xe0,smg[i]);
vDevice_Process(0xc0,0x01<<i);
i = (i+1)%8;
}
//-------矩阵键盘------------
unsigned char vScan_Keys()
{
unsigned char key_io=0xff;
P32=0;P33=0;
P34=1;P35=1;
if(P35==0) key_io=0xd0;
if(P34==0) key_io=0xe0;
P32=1;P33=1;
P34=0;P35=0;
if(P32==0) key_io=key_io|0x0b;
if(P33==0) key_io=key_io|0x07;
return key_io;
}
unsigned char Trg,Cont;
void vThree_line()
{
unsigned char key_io,ReadData;
key_io = vScan_Keys();
ReadData = key_io^0xff;
Trg = ReadData&(ReadData^Cont);
Cont = ReadData;
}
unsigned char cnt_key;
unsigned int cnt_k12;//长按1s计时
unsigned int cnt_k13;
void vKeys_Process()
{
if(cnt_key>=10)
{
cnt_key=0;
vThree_line();
if(Trg==0x18) //S16
{
if(mode1==1&&mode2==0)
{
pre1=pre1-2;
}
if(mode1==1&&mode2==1)
{
pre2=pre2-5;
}
}
if(Trg==0x14) //S17
{
if(mode1==1&&mode2==0)
{
pre1=pre1+2;
}
if(mode1==1&&mode2==1)
{
pre2=pre2+5;
}
}
//长按
if(Cont==0x28)//S12
{
cnt_k12++;//10ms加一次 100次就是1秒
}
if(Cont==0x24)
{
cnt_k13++;
}
if(Cont==0x00&&Trg==0x00)
{
if(cnt_k12>=100)
{
change_times=0;
vWrite_eeprom(0x20,change_times);
}
else if(cnt_k12!=0) //小于100且不等于0是短按
{
if(mode1==0)mode2 = (mode2+1)%3;
if(mode1==1)mode2 = (mode2+1)%2;
}
if(cnt_k13>=100)
{
dac_state=!dac_state;
}
else if(cnt_k13!=0)
{
mode1 = (mode1+1)%2;
if(mode1==0)//切回了数据界面,检查参数是否发生改变
{
if(pre1!=pram_temp) //如果参数发生了改变
{
pram_temp=pre1;
change_times++;
vWrite_eeprom(0x20,change_times);
}
else if(pre2!=pram_dist)
{
pram_dist=pre2;
change_times++;
vWrite_eeprom(0x20,change_times);
}
}
if(mode1==1) //切到参数界面时先把暂时pre改为真实参数pram
{
pre1 = pram_temp;
pre2 = pram_dist;
}
mode2=0;
}
cnt_k13=0;
cnt_k12=0;
}
}
}
//---------LED指示灯--------
void vLED_Process()
{
if(tempture>pram_temp*100)
{
led_ctrl.B.b1=0;
}
else
{
led_ctrl.B.b1=1;
}
if(dist>pram_dist)
{
led_ctrl.B.b2=0;
}
else
{
led_ctrl.B.b2=1;
}
if(dac_state==1)
{
led_ctrl.B.b3=0;
}
else
{
led_ctrl.B.b3=1;
}
vDevice_Process(0x80,led_ctrl.Hex);
}
/*----------------------------
发送串口数据
----------------------------*/
void SendData(unsigned char dat)
{
while (busy); //等待前面的数据发送完成
busy = 1;
SBUF = dat; //写数据到UART数据寄存器
}
/*----------------------------
发送字符串
----------------------------*/
void SendString(char *s)
{
while (*s) //检测字符串结束标志
{
SendData(*s++); //发送当前字符
}
}
//串口数据处理
bit flag_uart;
void vUart_Porcess()
{
if(flag_uart==1)
{
flag_uart=0;
if(rx_buf[0]=='S'&&rx_buf[1]=='T')
{
SendData('$');
SendData(dist/10+'0');SendData(dist%10+'0');SendData(',');
SendData(tempture/1000+'0');SendData(tempture/100%10+'0');SendData('.');SendData(tempture/10%10+'0');SendData(tempture%10+'0');
SendString("\r\n");
}
else if(rx_buf[0]=='P'&&rx_buf[1]=='A'&&rx_buf[2]=='R'&&rx_buf[3]=='A')
{
SendData('#');
SendData(pram_dist/10+'0');SendData(pram_dist%10+'0');SendData(',');
SendData(pram_temp/10+'0');SendData(pram_temp%10+'0');SendString("\r\n");
}
else
{
SendString("ERROR\r\n");
}
}
}
//系统初始化
void vSystem_init()
{
led_ctrl.Hex=0xff;
vDevice_Process(0x80,0xff);
vDevice_Process(0xa0,0x00);
}
void main()
{
vSystem_init();
Timer2Init();
UartInit();
while(1)
{
vSmg_Process();
vRead_temp();
vGet_distance();
vKeys_Process();
vUart_Porcess();
vDAC_out();
}
}
void Timer2_service() interrupt 12
{
vSmg_Show();
vLED_Process();
cnt_temp++;cnt_dist++;cnt_key++;cnt_dac++;
}
/*----------------------------
UART 中断服务程序
-----------------------------*/
void Uart() interrupt 4
{
if (RI)
{
RI = 0; //清除RI位
rx_buf[rx_cnt++]=SBUF;
if(rx_buf[rx_cnt-1]=='\n')
{
flag_uart=1;
rx_cnt=0;
}
}
if (TI)
{
TI = 0; //清除TI位
busy = 0; //清忙标志
}
}
IIC.c
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>
#define DELAY_TIME 5
sbit sda=P2^1;
sbit scl=P2^0;
void Delay5ms() //@12.000MHz
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
//EEPROM 存储
void vWrite_eeprom(unsigned char addr,unsigned char dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
Delay5ms();
}
//EEPROM 读取
unsigned char vRead_eeprom(unsigned char addr)
{
unsigned char dat;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return dat;
}
//DAC 模拟电压输出
void vOut_V(unsigned char dat)
{
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x40);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
onewire.c
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>
sbit DQ=P1^4;
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;i++);
}
}
//
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);
}
//
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;
}
//
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 vRead_18b20()
{
unsigned char LSB,MSB;
float temp;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
temp =((MSB<<8)|LSB)*0.0625;
return temp;
}