本人實力菜,望大佬手下留情,随手一記。
最近要鼓搗出5V的ds18b20用stm8采集,網上一搜發現大部分都是把資料端直接接到3.3的引腳,我也這麼做的。
用的DS18B20為淘寶外面有鋼管的那種,系統闆為STM8L051,第一次接觸stm8先去找的庫函數,以附件形式粘貼到下面。用IAR建工程一搜一大把。
單總線協定因為隻有一條線,時序很重要,肯定要使用延時函數,用的原子哥的延時函數,,照搬原子哥的代碼:http://www.openedv.com/posts/list/17347/htm
記得定義頭檔案時加上 #include "stm8l15x_conf.h",不然會報錯
#include "delay.h"
volatile u8 fac_us=0;
void delay_init(u8 clk)
{
if(clk>16)fac_us=(16-4)/4;
else if(clk>4)fac_us=(clk-4)/4;
else fac_us=1;
}
void delay_us(u16 nus)
{
__asm(
"PUSH A \n" //1T,壓棧
"DELAY_XUS: \n"
"LD A,fac_us \n" //1T,fac_us加載到累加器A
"DELAY_US_1: \n"
"NOP \n" //1T,nop延時
"DEC A \n" //1T,A--
"JRNE DELAY_US_1 \n" //不等于0,則跳轉(2T)到DELAY_US_1繼續執行,若等于0,則不跳轉(1T).
"NOP \n" //1T,nop延時
"DECW X \n" //1T,x--
"JRNE DELAY_XUS \n" //不等于0,則跳轉(2T)到DELAY_XUS繼續執行,若等于0,則不跳轉(1T).
"POP A \n" //1T,出棧
);
}
void delay_ms(u32 nms)
{
u8 t;
if(nms>65)
{
t=nms/65;
while(t--)delay_us(65000);
nms=nms%65;
}
delay_us(nms*1000);
}
因為我沒有顯示的東西,隻能用printf,在參考大佬「C_Aya」的文章,原文連結:https://blog.csdn.net/baweiyaoji/article/details/72812045 成功弄出來後,可以正常列印字元串,但一遇到帶參數的printf立馬記憶體爆炸,然後又在參考大佬「Dancer__Sky」的文章,原文連結:https://blog.csdn.net/Dancer__Sky/article/details/82284961得以成功列印。記得自己的頭檔案不要定義成這個名字"stdarg.h",我都不記得C有這個頭檔案了,不然你無法調用C的stdarg.h,将會出現錯誤。
現在就到了最關鍵的時候了,這一部分我參考的大佬石破天開 https://blog.csdn.net/u012166958/article/details/84872480
// 複位,主機給從機發送複位脈沖
void DS18B20_Rst(void)
{
DS18B20_Mode_Out();
delay_us(2);
DS18B20_DQ_OUT_Low; // 産生至少480us的低電平複位信号
delay_us(700);
DS18B20_DQ_OUT_High; // 在産生複位信号後,需将總線拉高
delay_us(3);
}
// 寫1位元組到DS18B20
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_Mode_Out();
for (j = 1; j <= 8; j++)
{
testb = dat & 0x01;
dat = dat >> 1;
if (testb)
{
DS18B20_DQ_OUT_Low;// 寫1
delay_us(2);
DS18B20_DQ_OUT_High;
delay_us(80);
}
else
{
DS18B20_DQ_OUT_Low;// 寫0
delay_us(78);
DS18B20_DQ_OUT_High;// 釋放總線
delay_us(2);
}
}
這兩部分延時不太一樣,貼出來大家可以試一試。注意引腳輸入不要弄錯成浮空輸入。
DS18B20 2.0版本,在之前基礎上添加了查詢序列号
當隻有一個DS18B20的時候
void DS18B20_Search_Rom(void) //函數位置放在初始化下方 ,讀取單個裝置的序列号
{
DS18B20_Write_Byte(0x33);
delay_us(2);
for(u8 j = 0; j <8; j++)
{
address[j] = DS18B20_Read_Byte();
}
} //重複讀取可能有點問題,建議放在while上邊
有多個DS18B20時,參考大佬 https://blog.csdn.net/u012166958/article/details/84872480
void DS18B20_Search_Rom(void)
{
u8 ReadBit,data;
u8 i,j,t = 0 ;
u8 chongtuwei;
u8 zhan[5];
u8 Sequence[64];//序列碼
DS18B20_Struct.ID_Num = 0;
do
{
// DS18B20_Rst(); //這裡我加上會出問題,是以我注釋掉了
// delay_us(450);
DS18B20_Write_Byte(0xF0);
delay_us(2);
for(i = 0;i < 8;i++)
{
data =0;
for(j = 0;j < 8;j++)
{
ReadBit = DS18B20_Read_2Bit();
ReadBit = ReadBit & 0x03;
data >>=1;
if(ReadBit == 0x01) //讀到的資料位0 寫0 此位為0的器件響應
{
DS18B20_Write_Bit(0);
Sequence[(i * 8 + j)] = 0;
}else if(ReadBit == 0x02)//讀到的資料位1 寫1 此位為1的器件響應
{
data = data|0x80;
DS18B20_Write_Bit(1);
Sequence[i * 8 + j] = 1;
}else if(ReadBit == 0x00) //讀到的資料位0,有沖突位,判斷沖突位
{
//如果沖突位大于棧頂寫0,小于棧頂寫以前資料,等于棧頂寫1
chongtuwei = i * 8 + j + 1;
if(chongtuwei > zhan[t])
{
DS18B20_Write_Bit(0);
Sequence[(i * 8 + j)] = 0;
zhan[++t] = chongtuwei;
}else if (chongtuwei < zhan[t])
{
data = data|((Sequence[(i * 8 + j)]&0x01)<<7);
DS18B20_Write_Bit(Sequence[(i * 8 + j)]);
}else if(chongtuwei == zhan[t])
{
data = data|0x80;
DS18B20_Write_Bit(1);
Sequence[(i * 8 + j)] = 1;
t--;
}
}else //沒搜尋到
{
}
}
DS18B20_Struct.DS18B20_ID[DS18B20_Struct.ID_Num][i] = data;
}
DS18B20_Struct.ID_Num++;//儲存搜尋到的個數
}while(zhan[t] !=0&&(DS18B20_Struct.ID_Num < ROM_ID));
}
主函數
void main(void)
{
sys_clock_init();//16MHZ工作
GPIO_Init(GPIOD,GPIO_Pin_0,GPIO_Mode_Out_PP_Low_Fast);//配置D0的工作模式
usart_init(115200);
delay_init(16);
while(DS18B20_Init());//初始化加檢測
DS18B20_Search_Rom();
while (1)
{
//DS18B20_Init();
i = DS18B20_Get_Temp();
mprintf("temp=%f",i);
}
}
最後大體是這個效果 版本1.0