#申请原创# https://bbs.21ic.com/icview-3248814-1-1.html
国产的18B20也是非常好用,轻松教你1分钟移植到M487
@21小跑堂
新唐提供的原例程在上述链接下载,接下来我们让这个例程的库函数统一到51单片机里去。
如何统一呢,其实就是实现延时函数的移植。
由于51单片机通常采用跑空指令延时的方法,因此我们这里要借助示波器即可很好的实现延时脉宽长度的测量,确保相差无几,即可实现完美移植。
原库函数如下所示,使用的是CLK_SysTickDelay()函数,这里我们替换它们即可。
- static void DS18B20_Reset(void)
- {
- uint8_t i;
- i = 1;
- while (i)
- {
- DQ = 0; //Send a low level reset signal
- CLK_SysTickDelay(480); //Delay at least 480us
- DQ = 1; //Release data line
- CLK_SysTickDelay(60); //Waiting for 60us
- i = DQ; //Detect the presence of pulses
- CLK_SysTickDelay(420); //Waiting for the device to release the data line
- }
- }
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] Read 1 byte data from DS18B20
- * @param None
- * [url=home.php?mod=space&uid=266161]@return[/url] u8dat: Read data
- */
- static uint8_t DS18B20_ReadByte(void)
- {
- uint8_t i;
- uint8_t u8dat = 0;
- for (i = 0; i < 8; i++)
- {
- u8dat >>= 1;
- DQ = 0; //Start time slice
- CLK_SysTickDelay(1); //Delay waiting
- DQ = 1; //Ready to receive
- CLK_SysTickDelay(1); //Reception delay
- if (DQ) u8dat |= 0x80; //Read data
- CLK_SysTickDelay(60); //Waiting for the end of time
- }
- return u8dat;
- }
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] Write 1 byte of data to the DS18B20
- * @param u8dat Write data
- * [url=home.php?mod=space&uid=266161]@return[/url] None
- */
- static void DS18B20_WriteByte(uint8_t u8dat)
- {
- uint8_t i;
- for (i = 0; i < 8; i++)
- {
- DQ = 0; //Start time slice
- CLK_SysTickDelay(1); //Delay waiting
- if (u8dat & 0x01) DQ = 1; //Send data
- CLK_SysTickDelay(60); //Waiting for the end of time
- DQ = 1; //Restore data line
- CLK_SysTickDelay(1); //Recovery delay
- u8dat >>= 1;
- }
- }
我们注意到一共有4种时长的延时,1us,60us,420us,480us
1us简单,我们引入头文件 #include<intrins.h> //包含_nop_()函数定义的头文件,如果不包含这个,可能会被编译器优化掉时长。
然后编写一个替换上面库函数的delay实现替换新唐BSP库函数的基于滴答定时器的延时
- void Delay(uint8_t i)
- {
- while(i--) _nop_();
- }
经过测试,定义如上的延时函数可以在晶振12MHz的情况下给8051提供一个比例为10:1的us级别延时
即Delay(48) 为480us,Delay(42)为420us,Delay(6)约为60us。具体误差很小这里不再说明,大家根据自己的实际情况可以用示波器进行测量。
以下简单的C51程序为我这次测量时候写大家简单函数。
- #include<reg51.h> //包含单片机寄存器的头文件
- #include<intrins.h> //包含_nop_()函数定义的头文件
- #define uchar unsigned char
- #define uint unsigned int
- #define uint8_t unsigned char
- #define int16_t unsigned int
- sbit DQ=P1^0;
- void Delay(uint8_t i)
- {
- while(i--) _nop_();
- }
- void main(void)
- {
- while(1)
- {
- DQ=1;
- Delay(6);
- DQ=0;
- Delay(6);
- }
- }
效果如何呢?利用这个方法就是一次点亮了。为了验证这个想法,把我上古年间在大学生跳蚤市场买的二手51开发板都拉出来了。
怎么样,学会了吗?
完成代码如下:
ds18b20.h
main.c
- /******************************************************************************************************************
- main.c 主文件
- *******************************************************************************************************************/
- #include<reg51.h> //包含单片机寄存器的头文件
- #include<intrins.h> //包含_nop_()函数定义的头文件
- #include"ds18b20.h"
-
- uchar value[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //定义0~9编码的数组,后面只需要调用数组
- uchar choice[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //定义数码管管位置编码数组,调用数组即可点亮对应的字
- /*用于扫描显示的延时,延时越长闪烁越严重,此处小于100效果较好,大于100晃动时候可以隐隐约约感觉到闪烁*/
- void delay(void)
- {
- uchar t;
- for(t=0;t<50;t++);
- }
- /*显示温度整数*/
- void DispLed_N(uint s)
- {
- /* 因为经过PNP三极管驱动,因此低电平导通三极管,然后由集电极供电给共阳极数码管的阳极。*/
- P2=~choice[3];
- P0=value[s%10];
- delay();
- P2=~choice[4];
- P0=value[s/10];
- delay();
- }
-
-
- /*显示温度小数*/
- void DispLed_D(uint s)
- {
- /* 因为经过PNP三极管驱动,因此低电平导通三极管,然后由集电极供电给共阳极数码管的阳极。*/
- P2=~choice[0];
- P0=value[s%10];
- delay();
- P2=~choice[1];
- P0=value[s/10];
- delay();
- }
-
- /*显示分割线*/
- void div(void)
- {
- P2=~choice[2];
- P0=0xbf;
- delay();
- }
- void main(void)
- {
- float t=15.0;
- while(1)
- {
- t = DS18B20_ReadTemperature() * 0.0625;
- DispLed_N((uint)(t));
- t=t-(uint)(t);
- t=t*100;
- DispLed_D((uint)(t));
- div();
- }
- }
-
|