蓝桥杯驱动准备-----对官方参考驱动的修改和编写方式和遇到的一些BUG及经验

    科技2024-02-19  110

    蓝桥杯驱动准备-----对官方参考驱动的修改和编写方式和遇到的一些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; // 读5次 uchar tim = 5; // num的值和i的值要相同 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; // 接收到应答信号为0; static flag=0; EA = 0; ack = init_ds18b20(); if(flag==1) { flag = 0; Write_DS18B20(0x4e); Write_DS18B20(0x1f);// 转换精度为0.5 } 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); //二进制小数部分转换为4位十进制 ledbuf[0] = temper_int / 100; ledbuf[1] = temper_int %100 /10; ledbuf[2] = temper_int %10; // 注意与0x7f显示小数点 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年数据包里的参考代码进行整理的

    Processed: 0.012, SQL: 8