蓝桥杯驱动准备-----对官方参考驱动的修改和编写方式和遇到的一些BUG
最主要的修改
最主要的就是延时的修改,因为他平时用的是普通的51单片机,属于12T单片机,但是对于IAP芯片是1T单片机,需要把延时修改为原来的10倍左右,同时还有一些细节地方的修改。 下面就不提延时的事情了,但是要记得留意一下
IIC驱动相关
AT24C02数据手册中的时序图
注意应答信号,0为应答,1为非应答 有关IIC的数据手册居然没有时间的详细说明。。。(这里是说比赛的时候发的数据手册里,模拟考试环境嘛)
原函数的修改
-注意在发送应答信号时,0为应答,1为非应答
在写读取ADC时,如果读取失败,可以使用多次读取的方法,然后选择最后一次读取的数,因为他比较稳定(或者读取几次,求平均值)
val
= IIC_RecByte();
while(--i
)
{
IIC_SendAck(0);
val
= IIC_RecByte();
}
上面的修改方式是读取最后一次的读数
uchar val
;
float num
;
uchar i
=5;
uchar tim
= 5;
num
= IIC_RecByte();
while(--i
)
{
IIC_SendAck(0);
num
+= IIC_RecByte();
}
val
= uint(num
/ tim
;
上面的修改方式是读取几次读数的平均值
在写ADC 和DAC的转换时可以选择使用仿真电路(蓝桥杯的Proteus仿真电路),然后使用虚拟示波器查看输出的电压值是否成功!!!!(或者直接去实验室找示波器用)
与EEPROM有关函数源代码
void write_iic(uchar ch
,uchar dat
)
{
bit flag
= 1;
iic_init();
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(ch
);
IIC_WaitAck();
IIC_SendByte(dat
);
flag
= IIC_WaitAck();
IIC_Stop();
}
uchar
read_iic(uchar ch
)
{
uchar dat
;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(ch
);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
dat
= IIC_RecByte();
IIC_SendAck(0);
IIC_Stop();
return dat
;
}
与PCF8591AD转换有关函数源代码
unsigned char read_adc(uchar ch
)
{
uchar val
;
uchar i
=5;
EA
= 0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(ch
);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
val
= IIC_RecByte();
while(--i
)
{
IIC_SendAck(0);
val
= IIC_RecByte();
}
IIC_SendAck(0);
IIC_Stop();
EA
= 1;
return val
;
}
void write_adc(uchar ch
,uchar val
)
{
uchar i
=255;
EA
= 0;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(ch
);
IIC_WaitAck();
IIC_SendByte(val
);
IIC_Stop();
EA
= 1;
return ;
}
在AD读取的时候,有的时候直接转换: Voltage = Voltage * 1.96; 会失败,可以用下面的方法:
ledbuf
[5] = voltage
*196/ 10000;
ledbuf
[6] = voltage
*196 / 1000 %10;
ledbuf
[7] = voltage
*196 /100 % 10;
ONEWIRE(单总线)驱动相关
数据手册中的时序图
初始化时序图:
读写时序图:
原函数的修改
接收到应答信号为0单总线对时序的要求很大,并且在0.0625的转换精度下转换速度很慢,一定要注意关总中断,不然很容易失败第一处修改:把原驱动的几乎每个延时都扩大10倍左右(就是最上面提到的延时问题)第二处修改:在Read_DS18B20函数中,把DQ=1;后面进行一个1us多点的延时,有了这个延时就可以正常读取数据了,没有的话就会瞎读数据,根据数据手册可以看出来,在读写的时候都要求有一个>1us的的拉低引脚的时间可以通过修改转换精度,来提快转换速度
void Write_DS18B20(unsigned char dat
)
{
unsigned char i
;
for(i
=0;i
<8;i
++)
{
DQ
= 0;
Delay_OneWire(2);
DQ
= dat
&0x01;
Delay_OneWire(50);
DQ
= 1;
dat
>>= 1;
}
Delay_OneWire(50);
}
unsigned char Read_DS18B20(void)
{
unsigned char i
;
unsigned char dat
;
for(i
=0;i
<8;i
++)
{
DQ
= 0;
Delay_OneWire(2);
dat
>>= 1;
DQ
= 1;
if(DQ
)
{
dat
|= 0x80;
}
Delay_OneWire(50);
}
return dat
;
}
第三处修改: 初始化函数中,把最后的代码改为等待DQ自动置位为1:
bit
init_ds18b20(void)
{
bit initflag
= 0;
DQ
= 1;
Delay_OneWire(12);
DQ
= 0;
Delay_OneWire(500);
DQ
= 1;
Delay_OneWire(55);
initflag
= DQ
;
while(!DQ
);
return initflag
;
}
与温度转换有关函数源代码
bit
Start18B20()
{
bit ack
;
static flag
=0;
EA
= 0;
ack
= init_ds18b20();
if(flag
==1)
{
flag
= 0;
Write_DS18B20(0x4e);
Write_DS18B20(0x1f);
}
if(ack
==0)
{
Write_DS18B20(0XCC);
Write_DS18B20(0x44);
}
EA
= 1;
return ~ack
;
}
bit
rd_temperature(unsigned int *temp
)
{
bit ack
;
unsigned char LSB
,MSB
;
EA
= 0;
ack
= init_ds18b20();
if(ack
==0)
{
Write_DS18B20(0XCC);
Write_DS18B20(0xBE);
LSB
= Read_DS18B20();
MSB
= Read_DS18B20();
*temp
= ((unsigned int)MSB
<< 8) + LSB
;
}
EA
= 1;
return ~ack
;
}
在主函数中的temp的处理: 对于默认转换经度0.0625
Temp_int
= Temp
>> 4;
Temp_dec
= Temp
& 0xF;
Temp_dec
= Temp_dec
* (10000 / 16);
ledbuf
[0] = temper_int
/ 100;
ledbuf
[1] = temper_int
%100 /10;
ledbuf
[2] = temper_int
%10;
ledbuf
[3] = temper_dec
/ 1000;
ledbuf
[4] = temper_dec
%1000 / 100;
ledbuf
[5] = temper_dec
% 100 / 10;
ledbuf
[6] = temper_dec
%10;
ds1302驱动相关
数据手册中的时序图
原函数的修改
这个可以说没有需要修改的地方,真好,注意好BCD码和十进制码的转换就行
十进制码= BCD码 / 16 * 10 + BCD码 % 16;BCD码 = 十进制码%10 * 16 + 十进制码 %10 ;
与时间读写有关函数源代码
void write_time(uchar shi
,uchar fen
,uchar miao
)
{
EA
= 0;
Ds1302_Single_Byte_Write(0x8e,0);
Ds1302_Single_Byte_Write(0x80,(miao
/10)*16+miao
%10);
Ds1302_Single_Byte_Write(0x82,(fen
/10)*16+fen
%10);
Ds1302_Single_Byte_Write(0x84,(shi
/10)*16+shi
%10);
Ds1302_Single_Byte_Write(0x8e,0x80);
EA
= 1;
}
读取时间的时候注意别忘了BCD码和十进制码之间的转换就行,然后就是要让(地址 |0x01)
shi
= Read_Ds1302_Byte(0x84 | 0x01);
fen
= Read_Ds1302_Byte(0x82 | 0x01);
miao
= Read_Ds1302_Byte(0x80 | 0x01);
shi
= shi
/16 * 10 + shi
% 16;
fen
= fen
/16 * 10 + fen
% 16;
miao
= miao
/16 * 10 + miao
% 16;
到这里来说,应该是全部完成了。
以上代码都是根据2019年数据包里的参考代码进行整理的