【STM32】stm32f407 + DS18B20 碰出不一樣的火花

Author:AXYZdong 自動化專業 工科男
有一點思考,有一點想法,有一點理性!
定個小小目標,努力成爲習慣!在最美的年華遇見更好的自己!
CSDN@AXYZdong,CSDN首發,AXYZdong原創
唯一博客更新的地址爲: 👉 AXYZdong的博客 👈

在這裏插入圖片描述

▲ 碰撞、火花


前言

之前在這篇文章:【STM32學習記錄4】1.44寸TFT液晶屏顯示字符、漢字和圖片
賣了一個關子:
在這裏插入圖片描述
今天把這個給補上。點擊下載完整工程

  • 開發板:stm32f407VET6
  • 開發環境:keil5 MDK

一、硬件基礎——DS18B20

1.DS18B20簡介

在這裏插入圖片描述

2.硬件連接

根據手冊,DS18B20的硬件接法很簡單,分爲以下兩種:

需要注意的是不管哪一種接法DQ上一定要接個上拉電阻

1.【寄生接法】

DS18B20_GND \to STM32F407_GND

DS18B20_VCC \to STM32F407_GND

DS18B20_DQ \to STM32F407_P**

DQ引腳可接任意IO口

關於寄生方式,需要注意以下幾點:

  • DS18B20的寄生方式是在DQ引腳爲高電平時“竊取”電源,同時將部分能量存儲在內部的電容裏。
    所以,上拉電阻!!一定要接上!!

  • 爲了使DS18B20準確完成溫度轉換,當溫度轉換髮生時,IO口必須提供足夠大的功率。
    DS18B20的工作電流高達1mA,5K的上拉電阻使得IO口沒有足夠的驅動能力。
    如果多個DS18B20在同一個IO上而且同時進行溫度的變換時,這個問題將特別尖銳。

2.【正常供電】

DS18B20_GND \to STM32F407_GND

DS18B20_VCC \to STM32F407_VCC

DS18B20_DQ \to STM32F407_P**

參考文章:https://blog.csdn.net/weixin_40774605/article/details/88557470

關於 DQ上一定要接個上拉電阻 這個問題,我做的時候是沒有接上拉電阻的,但是也可以讀到溫度。emmm,有點玄學了。

3.單總線協議

在這裏插入圖片描述

執行序列 通過單線總線端口訪問 DS18B20 的協議如下:

  • 步驟1. 初始化
  • 步驟2. ROM 操作指令
  • 步驟3. DS18B20 功能指令

步驟1. 初始化

通過單總線的所有執行操作處理都從一個初始化序列開始。初始化序列包括一個由總線控制器發出的復位脈衝和其後由從機發出的存在脈衝。存在脈衝讓總線控 制器知道 DS18B20 在總線上且已準備好操作。

步驟2. ROM 操作指令

一旦總線控制器探測到一個存在脈衝,它就發出一條 ROM 指令。如果總線上掛有 多隻 DS18B20,這些指令將基於器件獨有的 64 位 ROM 片序列碼使得總線控制器 選出特定要進行操作的器件。這些指令同樣也可以使總線控制器識別有多少隻, 什麼型號的器件掛在總線上,同樣,它 們也可以識別哪些器件已經符合報警條件。ROM 指令有 5 條,都是 8 位長度。總線控制器在發起一條 DS18B20 功能指令之前必須先發出一條 ROM 指令。

步驟3. DS18B20 功能指令

在總線控制器發給欲連接的DS18B20一條ROM命令後,跟着可以發送一條 DS18B20 功能指令。這些命令允許總線控制器讀寫 DS18B20 的暫存器,發起溫度轉換和識別電源模式。

插播一條反爬蟲信息,讀者可以忽略:


在這裏插入圖片描述

二、編程思路

在這裏插入圖片描述

DS18B20.h


// =============================================
# @Time    : 2020-06-08
# @Author  : AXYZdong
# @CSDN    : https://blog.csdn.net/qq_43328313
# @FileName: DS18B20.h
# @Software: keil5 MDK
// =============================================

#ifndef __DS18B20_H
#define __DS18B20_H
#include "stm32f4xx.h"
 
/************************** DS18B20 連接引腳定義********************************/
#define    RCC_DS18B20                          RCC_AHB1Periph_GPIOB
#define    DS18B20_DQ_GPIO_PORT                 GPIOB
#define    DS18B20_DQ_GPIO_PIN                  GPIO_Pin_6

/************************** DS18B20 函數宏定義********************************/
#define    DS18B20_DQ_L	            GPIO_ResetBits ( DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN ) 
#define    DS18B20_DQ_H	            GPIO_SetBits ( DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN ) 

#define    DS18B20_DQ_IN()	        GPIO_ReadInputDataBit ( DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN ) 


/************************** DS18B20 函數聲明 ********************************/

void DS18B20_Init(void);
void display(char *tab);


#endif /* __DS18B20_H */

DS18B20.c


// =============================================
# @Time    : 2020-06-08
# @Author  : AXYZdong
# @CSDN    : https://blog.csdn.net/qq_43328313
# @FileName: DS18B20.c
# @Software: keil5 MDK
// =============================================

#include "stm32f4xx.h"
#include "ds18b20.h"
#include "delay.h"
 
/*******************************************************************************
 * 函數名:DS18B20_GPIO_Config
 * 描述  :配置DS18B20用到的I/O口
 * 輸入  :無
 * 輸出  :無
 *******************************************************************************/
void DS18B20_GPIO_Config(void)
{ 
    GPIO_InitTypeDef GPIO_InitStructure; 
    RCC_AHB1PeriphClockCmd(RCC_DS18B20, ENABLE);       /*開啓DS18B20對應的GPIO的外設時鐘*/ 
    GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_GPIO_PIN; /*選擇要控制的DS18B20引腳*/ 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;      /*設置引腳模式輸出模式*/       
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     /*設置引腳的輸出類型爲推輓輸出*/
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  /*設置引腳速率爲50MHz */ 
    GPIO_Init(DS18B20_DQ_GPIO_PORT, &GPIO_InitStructure); /*調用庫函數,初始化相應GPIO*/
}
/*******************************************************************************
 * 函數名:DS18B20_Mode_Out
 * 描述  :使DS18B20-DATA引腳變爲輸出模式
 * 輸入  :無
 * 輸出  :無
 *******************************************************************************/
static void DS18B20_Mode_Out(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
	 	/*選擇要控制的DS18B20_DQ_GPIO_PORT引腳*/															   
  	GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_GPIO_PIN;	
	/*設置引腳模式輸出模式*/
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;   
  /*設置引腳的輸出類型爲推輓輸出*/     
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	/*設置引腳速率爲50MHz */   
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	/*調用庫函數,初始化DS18B20_DQ_GPIO_PORT*/
  	GPIO_Init(DS18B20_DQ_GPIO_PORT, &GPIO_InitStructure);
}
/*******************************************************************************
 * 函數名:DS18B20_Mode_IN
 * 描述  :使DS18B20-DATA引腳變爲輸入模式
 * 輸入  :無
 * 輸出  :無
 *******************************************************************************/
static void DS18B20_Mode_IN(void)
{
 	  GPIO_InitTypeDef GPIO_InitStructure;

	  	/*選擇要控制的DS18B20_DQ_GPIO_PORT引腳*/	
	  GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_GPIO_PIN;

	   /*設置引腳模式爲浮空輸入模式*/ 
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;	

	  /*調用庫函數,初始化DS18B20_DQ_GPIO_PORT*/
	  GPIO_Init(DS18B20_DQ_GPIO_PORT, &GPIO_InitStructure);
}

void DS18B20_Init()
{
  DS18B20_GPIO_Config();
}
 
/*******************************************************************************
 * 函數名:DS18B20_Reset
 * 描述  :初始化DS18B20
 * 輸入  :無
 * 輸出  :無
 * 返回值:初始化成功爲0,不成功爲1
 *******************************************************************************/
int DS18B20_Reset(void) 
{      
	DS18B20_Mode_Out();
	int initflag = 0;
    DS18B20_DQ_H;        //先置高
    delay_us(700);       //延時700us,使總線穩定
    DS18B20_DQ_L;        //復位脈衝,低電位
    delay_us(750);       //保持至少480us,這裏500us
    DS18B20_DQ_H;        //拉高數據線,釋放總線
    delay_us(40);        //等待15-60us,這裏33us
	DS18B20_Mode_IN();
    initflag = GPIO_ReadInputDataBit(DS18B20_DQ_GPIO_PORT,DS18B20_DQ_GPIO_PIN);	
    delay_us(60);
	  return initflag;
}

/*******************************************************************************
* 函數名:DS18B20_Wbyte
* 功能:寫一個字節
* 輸入:uint8_t xbyte
* 輸出:無
* 返回值:無
* 備註:無
*******************************************************************************/
void Write_DS18B20(unsigned char xbyte)
{
	int8_t i ,x = 0;
	DS18B20_Mode_Out();
    //8次循環實現逐位寫入
    for(i = 1; i <= 8; i++)
    {
        //先取低位
        x = xbyte & 0x01;
        //寫1
        if(x)
        {
            DS18B20_DQ_H;
            //拉低總線
            DS18B20_DQ_L;
            //延時15us
            delay_us(15);
            //總線寫1
            DS18B20_DQ_H;
            //延時15us
            delay_us(15);
            //保持高電平
            DS18B20_DQ_H;
            delay_us(4);
        }
        //寫0
        else
        {
            DS18B20_DQ_H;
            //總線拉低
            DS18B20_DQ_L;
            //延時15us
            delay_us(15);
            //總線寫0
            DS18B20_DQ_L;
            //延時15us
            delay_us(15);
            //保持高電平
            DS18B20_DQ_H;
            delay_us(4);
        }
        //xbyte右移一位
        xbyte = xbyte >> 1;
    }
}

/*******************************************************************************
* 函數名:DS18B20_Rbit
* 功能:從DS18B20讀一個位
* 輸入:無
* 輸出:無
* 返回值:讀取到的位
* 備註:無
*******************************************************************************/
uint8_t DS18B20_Rbit(void)
{
    //rbit是最終位數據,x是取狀態變量
    uint8_t rbit = 0x00,x = 0;
	  DS18B20_Mode_Out(); //改變DQ爲輸出模式
    
    DS18B20_DQ_H;    
    DS18B20_DQ_L;
    delay_us(1);
    DS18B20_DQ_H;
	
    //延時大約3us
    //delay_us(7);
    //獲取總線電平狀態
    x = DS18B20_DQ_IN();
    //如果是1,則返回0x80,否則返回0x00
    if(x)
        rbit = 0x80;
    //延時大約60us
    delay_us(60);
    return rbit;
}
/*******************************************************************************
* 函數名:DS18B20_Rbyte
* 功能:從DS18B20讀一個字節
* 輸入:無
* 輸出:無
* 返回值:讀取到的字節
* 備註:無
*******************************************************************************/
uint8_t DS18B20_Rbyte(void)
{
    //rbyte:最終得到的字節
    //tempbit:中間運算變量
    uint8_t rbyte = 0,i = 0, tempbit =0;
    for (i = 1; i <= 8; i++)
    {
        //讀取位
        tempbit = DS18B20_Rbit();
        //右移實現高低位排序
        rbyte = rbyte >> 1;
        //或運算移入數據
        rbyte = rbyte|tempbit;
    }
    return rbyte;
}
/*******************************************************************************
* 函數名:ReadTemperature
* 功能:讀取溫度
* 輸入:無
* 輸出:溫度值
* 返回值:無
* 備註:注意溫度的轉換
*******************************************************************************/
int ReadTemperature(void) 
{   
    int fg;        //fg:符號位
    int data;      //data:溫度的整數部分
	  float f_data;  //f_data:溫度(浮點型)
    
    DS18B20_Reset();      //DS18B20初始化    
    Write_DS18B20(0xcc);  //跳過讀序列號   
    Write_DS18B20(0x44);  //啓動溫度轉換   
    delay_us(200);        //等待溫度轉換
    DS18B20_Reset();      //DS18B20初始化
    Write_DS18B20(0xcc);  //跳過讀序列號   
    Write_DS18B20(0xbe);  //讀溫度寄存器
	
    uint8_t TempL = DS18B20_Rbyte();
    uint8_t TempH = DS18B20_Rbyte();
    //符號位爲負
    if(TempH > 0x70)
    {
        TempL = ~TempL;
        TempH = ~TempH;
        fg = 0;
    }
    else 
        fg = 1;
    //整數部分
    data = TempH;
    data <<=  8;
    data = data | TempL;
    f_data = data*0.0625;
		data = f_data *10 ;
    if(fg)
        return data;
    else
        return -data;
}
/*******************************************************************************
* 函數名:display
* 功能:顯示溫度
* 輸入:*tab
* 輸出:溫度值
* 返回值:無
* 備註:注意溫度的轉換
*******************************************************************************/
void display(char *tab)
{
  tab[0] = ReadTemperature()/100 + 0x30;
	tab[1] = ReadTemperature()%100/10 + 0x30;
	tab[3] = ReadTemperature()%10 + 0x30;
	tab[2] = '.';
	tab[4] = 'C';
}

若果要移植代碼,只需修改頭文件中 DS18B20 連接引腳定義


三、效果

在這裏插入圖片描述

總結

  • 寫驅動的時間不是很長的,也有很多源碼,參考修改即可。

  • 最關鍵的還是後期的調試,以及把讀出來的溫度顯示到 TFT 屏上

  • 單總線的時序也要關注,不同開發板的頻率不同,延時也有差異。


  本次的分享就到這裏


11

好書不厭百回讀,熟讀自知其中意。將學習成爲習慣,用知識改變命運,用博客見證成長,用行動證明努力。
如果我的博客對你有幫助、如果你喜歡我的博客內容,請 “點贊” “評論” “收藏” 一鍵三連哦!
聽說 👉 點贊 👈 的人運氣不會太差,每一天都會元氣滿滿呦!^ _ ^ ❤️ ❤️ ❤️
碼字不易,大家的支持就是我堅持下去的動力。點贊後不要忘了👉關注👈我哦!
更多精彩內容請前往 AXYZdong的博客


如果以上內容有任何錯誤或者不準確的地方,歡迎在下面👇留個言。或者你有更好的想法,歡迎一起交流學習~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章