3.1 DS18B20检测温度,LCD显示
这个东东也是调了好多天,最后不知为啥早上就可以工作了,真奇妙,先上图
一开始想自己写源程序的,可是最后DS18B20总是不响应,最后只得又换了源程序,只是修改了下温度的算法,在此把源程序贴上,供大家修改指正
void main(void)
{
float num;
char b[250];
RCC->CFGR|=0x00180002;
RCC->CR|=0x01000001;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG
| RCC_APB2Periph_AFIO , ENABLE);
/*------------------- Resources Initialization -----------------------------*/
LCD_Clear(Magenta);
LCD_SetTextColor(Blue);
LCD_SetBackColor(Magenta);
LCD_DisplayString(50, 50, "the temperature is");
STM32_LCD_Demo();
while(1)
{
num=readtemperature();
sprintf(b," %f",num);
LCD_DisplayString(50, 80, (uint8_t*)b);
delay_1ms(10);
}
}
void STM32_LCD_Demo(void)
{
/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG and AFIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG
| RCC_APB2Periph_AFIO , ENABLE);
/*------------------- Resources Initialization -----------------------------*/
/* GPIO Configuration */
GPIO_Config();
/* Initialize the LCD */
STM3210E_LCD_Init();
}
最后是DS18B20的程序,由于使用时钟滴答器即时较准,一开始以为蛮难的,其实很简单的,就跟设置定时器一样简单。
#include "stm32f10x_gpio.h"
#define DS_PORT GPIOA //选择外设GPIOA
#define DS_DQIO GPIO_Pin_1 //选择管脚Pa1
#define ResetDQ() GPIO_ResetBits(DS_PORT,DS_DQIO) //拉低DQ
#define SetDQ() GPIO_SetBits(DS_PORT,DS_DQIO) //拉高DQ
#define GetDQ() GPIO_ReadInputDataBit(DS_PORT,DS_DQIO) //读取DQ的电平
#define skipRom 0xcc
#define convert 0x44
#define readTemp 0xbe
void delay_1ms(uint16_t cnt)
{
uint16_t i;
while(cnt--)
for(i=0;i<8300;i++);
}
void delay_1us(uint32_t value)
{
SysTick->LOAD=value*9; //时间加载
SysTick->CTRL|=0x01; //开始倒数
while(!(SysTick->CTRL&(1<<16))); //等待时间到达
SysTick->CTRL=0x00000000; //关闭计数器
SysTick->VAL=0x00000000; //清空计数器
}
void Init_ds18b20(void) //初始化DS18B20
{
GPIOA->CRL=0x44444474;
SetDQ();
delay_1us(30); //保持高电平一段时间时间
ResetDQ(); //总线将其拉低电平
delay_1us(600); //延时400us-960us,这里延时600us
SetDQ(); //总线释放低电平
delay_1us(30); //延时15us-60us,这里延时30us
GPIOA->CRL&=0xFFFFFF4F;
while(GetDQ()); //若为高电平则出错,等待一直循环
delay_1us(500); //将剩余时间消耗完
SetDQ(); //总线将电平拉高
}
void DS18B20WriteByte(uint8_t Dat)
{
uint8_t i;
GPIOA->CRL=0x44444474;
for(i=8;i>0;i--)
{
ResetDQ(); //在15us内送数到数据线,在15-60us内采样
delay_1us(5);
if(Dat&0x01) //读数据的最低位
SetDQ();
else
ResetDQ();
delay_1us(65); //将剩余时间消耗完
SetDQ();
delay_1us(2); //写两个位之间间隔大于1us
Dat>>=1; //右移一位,
}
}
uint8_t DS18B20ReadByte(void)
{
uint8_t i,Dat;
//SetDQ();
//delay_1us(5);
for(i=0;i<8;i++)
{
GPIOA->CRL=0x44444474;
SetDQ(); //拉高总线
delay_1us(5);
Dat>>=1;
ResetDQ(); //从读时序开始到采样信号线必须在15us内,且采样尽量安排在15us最后
delay_1us(5);
SetDQ(); //释放总线,然后才能进行采样,否则无意义。只有低电平
delay_1us(5);
GPIOA->CRL&=0xFFFFFF4F;
if(GetDQ())
Dat|=0x80;
else
Dat&=0x7f;delay_1us(5);
delay_1us(65); //消耗剩余时间
}
return Dat;
}
float readtemperature(void)
{
uint8_t a,b;
float cach;
Init_ds18b20(); //初始化
DS18B20WriteByte(skipRom);
DS18B20WriteByte(convert); //开始转换温度
delay_1ms(550); //延时,等待温度转换完成
Init_ds18b20();
DS18B20WriteByte(skipRom);
DS18B20WriteByte(readTemp); //读取暂存器
a=DS18B20ReadByte(); //读取低8位
b=DS18B20ReadByte(); //读取高8位
if(b&0xF8)
{
a=~a;
cach=a&0x0F;
cach=(cach+1)*0.0625;
b=~b;
b<<=4;
b+=(a&=0xf0)>>4;
cach+=b;
return cach;
}
else
{
cach=a&0x0F;
cach*=0.0625;
b<<=4;
b+=(a&=0xf0)>>4;
cach+=b;
return cach;
}
}