自己刷省赛的一些总结,有不足之处还望指正。
-
首先说一些读温度吧,元器件叫Ds18b20
官方提供的代码是onewire.h与onewire.c,但有一点要注意的是:
void Delay_OneWire(unsigned int t) //STC89C52RC
{
while(t--);
}
//我们需要给他加长12倍,因为我们蓝桥杯用的是stc15f系列。
void Delay_OneWire(unsigned int t) //STC89C52RC
{
while(t--)
{
unsigned char i = 0;
for (i = 0; i < 12; i++);
}
}
温度的读取代码,可以直接去网上找,我提供些细节:考题中有保留两位和一位或者无小数的读取。
我们开始需要知道:temp前5位为符号位,中间七位为整数,后面四位为小数。
我的建议是:定义一个 unsigned int temp;temp=((high&0x0f)<<8)|low;temp=temp*0.625;//一位小数,构成一个三位数(temp=temp*6.25;四位数,保留两位。temp=temp*0.0625;两位数,无小数)
代码:
unsigned int read_temp(){
unsigned int temp;
unsigned char high,low;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low=Read_DS18B20();
high=Read_DS18B20();
temp=high&0x0f;
temp=((temp<<8)|low)*0.625;
return temp;
}
2.再说下时钟读取,Ds1302:
官方提供的是ds1302.h与ds1302.c。我感觉这没啥注意的,感觉要注意的就是16进制数存入,16进制读取。
代码:
void Read_time(unsigned char *time){
unsigned char i;
for(i=0;i<3;i++){
time[i]=Read_Ds1302_Byte(0x85-2*i);
}
}
void Write_time(unsigned char *time){
unsigned char i;
Write_Ds1302_Byte(0x8e,0);
for(i=0;i<3;i++){
Write_Ds1302_Byte(0x84-2*i,time[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
3.电压的读取,pcf8591:
官方提供的是iic.h与iic.c。pcf8591有adc电压读取(分0x01光敏电阻读电压,0x03滑动变阻器RB2电压读取),dac电压存入,即dac输出。如果单单用到DAC输出的话,控制寄存器地址就是0x40。
在读取电压中,我的建议是:adc读取时unsigned int voltage;voltage=X*500/255;(V=X*1.961)要写括号这种,所得三位数,为电压扩大100倍。//x表示取出的值;
代码:
unsigned int Pcf_read(unsigned char dat){//dat==0x01或0x03
unsigned int valtage=0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
voltage=IIC_RecByte()*1.921;
IIC_SendAck(1);
IIC_Stop();
return voltage;
}
注意adc读取时, IIC_SendAck(1);//等待应答,如果写这句话的话,记得中间值是1,同时写在IIC_Stop()之前。
dac存入中,我的建议:X=Voltage*255/500;(X=Voltage*51/100;)
代码:
void Pcf8591_dac(unsigned char date){
IIC_Start();
IIC_Sendbyte(0x90);
IIC_Waitack();
IIC_Sendbyte(0x40);//如果单单用到DAC输出的话,控制寄存器地址就是0x40。如果是滑阻输入然后DAC输出的话,
//就是0x43。
IIC_Waitack();
IIC_Sendbyte(date);
iIIC_Waitack();
IIC_Stop();
}
4.数据的存储与读出,at24c02(Eeprom)
官方提供的也是iic.h与iic.c。AT24C02提供2048位的电可擦和可编程只读存储器(EEPROM)组织为256, 8位字。注意adc读取时, IIC_SendAck(0);//与上面电压不同
代码:
void E2prom_write(unsigned char date,unsigned char add){
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(date);
IIC_WaitAck();
IIC_Stop();
}
unsigned char E2prom_read(unsigned char add){
unsigned char num;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
num=IIC_RecByte();
IIC_SendAck(0);
IIC_Stop();
return num;
}
5.频率的测量,P34与SIGNAL连接 ,TMOD=0x16,TH0=0xff,TL0=0xff,TH1与TL1自己设计,通过计数器0进行计数;这里官方没提供参考代码。TH1表示高8位,TL1表示低8位。其求1秒内的计数.
代码:
void Timer_init(){
TMOD=0x16;
TH0=0xff;
TL0=0xff;
TH1=(65536-1000)/256;//1毫秒的定时器
TL1=(65536-1000)%256;
EA=1;
ET0=1;
ET1=1;
TR0=1;
TR1=1;
}
void Timer_0() interrupt 1{
count++;
}
void Timer_1() interrupt 3{
TH1=(65536-1000)/256;//手动初始化
TL1=(65536-1000)%256;
if(++count_time>=1000){
count_time=0;
count_num=count;//count_num为测得的频率值
count=0;
}
}
6.按键
代码:
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
uchar key_old,key_long_flag,key_long_time_flag;
uint key_long_time=0
unsigned char Key_read(){
unsigned char num;
unsigned int key_val=0;
P34=P35=P42=P44=1;
P34=0;
key_val=P3;
P34=1,P35=0;
key_val=(key_val<<4)|(P3&0x0f);
P35=1,P42=0;
key_val=(key_val<<4)|(P3&0x0f);
P42=1,P44=0;
key_val=(key_val<<4)|(P3&0x0f);
switch(~key_val){
case 0x0008:num=4;break;
case 0x0004:num=5;break;
case 0x0002:num=6;break;
case 0x0001:num=7;break;
case 0x0080:num=8;break;
case 0x0040:num=9;break;
case 0x0020:num=10;break;
case 0x0010:num=11;break;
case 0x0800:num=12;break;
case 0x0400:num=13;break;
case 0x0200:num=14;break;
case 0x0100:num=15;break;
case 0x8000:num=16;break;
case 0x4000:num=17;break;
case 0x2000:num=18;break;
case 0x1000:num=19;break;
default :num=0;break;
}
return num;
}
void key_prc(){
uchar key_up,key_down,key_val;
key_val=Key_read();
key_down=key_val&(key_val^key_old);//按下瞬间,key_down为1,key_up为0,按住的过程都为0
key_up=(~key_val)&(key_val^key_old);//抬起数据为1
if(key_down==12){//12按键按下
}
//对13按键进行2s长按键测试
if(key_down==13){//key_down按下
key_long_flag=1;
key_long_time=0;
key_long_time_flag=0;
}
if(key_up==13)//按键抬起
{
key_long_flag=0;
key_long_time=0;
key_long_time_flag=0;
}
key_old=key_val;
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初始值
TH0 = 0xD4; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void Timer0_Service() interrupt 1{
key_time=(key_time+1)%10;
if(key_long_flag==1){
key_long_time=(key_long_time+1)%2000;
}
if(key_long_time==0&&key_long_flag==1){
key_long_time_flag=1;
key_long_flag=0;
}
}
void main(){
Timer0Init();//一些初始化我就不配置了,比如关灯关闭蜂蜜器之类的
while(1){
if(!key_time){//10ms扫描一次按键
key_prc();
if(key_long_time_flag){//key13长按2sy以上
key_long_time_flag=0;
}
}
}
}
最后说点小总结,上面是模块化的总结
继电器L10为Y5中的P04;即P0=0x10;蜂鸣器Buzz为Y5中的P06;即P0=0x40;
LED或者数码管显示出现闪烁,说明他们间隔时间太长。