1、新建一个工程模板
2、搭建一个显示平台
由于我使用的是STM32mini板,且还没带LCD,所以我要想操作STM32,并用DS18B20采取温度数据之前,需要一个显示器,这里我手头有一块1602,所以先让它在STM32上跑起来。
做好之后大概就是这个样子。
由于STM32没有1602的库,所以要自己写,1602的操作相对来说还是比较简单的。
/******************************************************
建立一个1602的头函数
用于:使能端口定义
数据端口定义
函数声明
******************************************************/
#include "stm32f10x.h"
#ifndef __lcd1602_H
#define __lcd1602_H
#define uchar unsigned char
//使能端口定义
#define LCD162A_RS PCout(8)
#define LCD162A_RW PCout(7)
#define LCD162A_E PCout(6)
//数据端口定义
#define DATAOUT(x) GPIOA->ODR=(GPIOA->ODR&0xff00)|(x&0x00FF); //Pa0-Pa7
// 函数声明
void lcd162a_WriteCommand(u8 CMD);
void lcd162a_WriteData(u8 dataW);
void lcd_init(void);
#endif
接下来就是1602的相关函数的编写
/*********************************************************
建立一个1602的C文件
用于:相关函数的编写
**********************************************************/
#include "lcd1602.h"
#include "delay.h"
#include "stm32f10x.h"
//写命令
void lcd162a_WriteCommand(u8 CMD)
{
delay_ms(2);
LCD162A_RS=0;
LCD162A_RW=0;
LCD162A_E=1;
DATAOUT(CMD);
delay_us(2);
LCD162A_E=0;
}
//写数据
void lcd162a_WriteData(u8 dataW)
{
delay_ms(2);
LCD162A_RS=1;
LCD162A_RW=0;
LCD162A_E=1;
DATAOUT(dataW);
delay_us(2);
LCD162A_E=0;
}
//初始化,主要用于IO的声明和使能
//这里我学会了两种方法,一个是函数法,另一个是寄存器法;读懂寄存器发首先要了解GPIO口相关寄存器的使用
void lcd_init(void)
{
// GPIO_InitTypeDef* GPIO_InitStruct;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE); //使能PA,PD端口时钟
// //设置PA0-PA7
// GPIO_InitStruct->GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
// GPIO_InitStruct->GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
// GPIO_InitStruct->GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_Init(GPIOA, GPIO_InitStruct);
// GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //置1
// //设置PC6-PC8
// GPIO_InitStruct->GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
// GPIO_InitStruct->GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
// GPIO_InitStruct->GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_Init(GPIOC, GPIO_InitStruct);
// GPIO_SetBits(GPIOC,GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8); //pc6-pc9 置1
/****************************************************************
寄存器的写法与注释
*****************************************************************/
RCC->APB2ENR|=1<<2;
RCC->APB2ENR|=1<<4; //使能PA,PD端口时钟
GPIOA->CRL=0X33333333; //PA0-7 推挽输出
GPIOA->ODR|=0X00FF; //PA0-7 端口置1
//pc6-pc9
GPIOC->CRH&=0XFFFFFF00; //清掉PC8 9原来的设置
GPIOC->CRL&=0X00FFFFFF; //清掉PC6 7原来的设置
GPIOC->CRH|=0X00000033; //PC8 9 推挽输出
GPIOC->CRL|=0X33000000; //PC6 7 推挽输出
GPIOC->ODR|=0X03C0; //pc6-pc9 置1
LCD162A_E=0;
lcd162a_WriteCommand(0x38); //设置16*2显示,5*7点阵,8位数据接口
lcd162a_WriteCommand(0x0c); //设置开显示,不显示光标
lcd162a_WriteCommand(0x06); //写一个字符后地址指针加一
lcd162a_WriteCommand(0x01); //显示清0,数据指针清零
}
上面这块完成之后,LCD1602基本上能显示数据了。
接下来就是调用STM32 中的DS18B20的库,使用其中的相关函数。我用的是原子哥的板子,当然用的也是他们的函数,向原子哥致敬,这里我贴出来,方便我日后理解。
#ifndef __DS18B20_H
#define __DS18B20_H
#include "sys.h"
//IO方向设置
#define DS18B20_IO_IN() {GPIOB->CRL&=0XFFFFFFF0;GPIOB->CRL|=8<<0;}
#define DS18B20_IO_OUT() {GPIOB->CRL&=0XFFFFFFF0;GPIOB->CRL|=3<<0;}
IO操作函数
#define DS18B20_DQ_OUT PBout(0) //数据端口 PA0
#define DS18B20_DQ_IN PBin(0) //数据端口 PA0
u8 DS18B20_Init(void); //初始化DS18B20
short DS18B20_Get_Temp(void); //获取温度
void DS18B20_Start(void); //开始温度转换
void DS18B20_Write_Byte(u8 dat);//写入一个字节
u8 DS18B20_Read_Byte(void); //读出一个字节
u8 DS18B20_Read_Bit(void); //读出一个位
u8 DS18B20_Check(void); //检测是否存在DS18B20
void DS18B20_Rst(void); //复位DS18B20
#endif
#include "ds18b20.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK miniSTM32开发板
//DS18B20驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//复位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //SET PA0 OUTPUT
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us
DS18B20_DQ_OUT=1; //DQ=1
delay_us(15); //15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//SET PA0 INPUT
while (DS18B20_DQ_IN&&retry<200)
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)return 1;
return 0;
}
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void) // read one bit
{
u8 data;
DS18B20_IO_OUT();//SET PA0 OUTPUT
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN();//SET PA0 INPUT
delay_us(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
delay_us(50);
return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//SET PA0 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DS18B20_DQ_OUT=0;// Write 1
delay_us(2);
DS18B20_DQ_OUT=1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT=0;// Write 0
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
//开始温度转换
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PORTA口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_0); //输出1
DS18B20_Rst();
return DS18B20_Check();
}
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}else temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换
if(temp)return tem; //返回温度值
else return -tem;
}
/******************************************************
主 函 数
*******************************************************/
#include "stm32f10x.h"
#include "lcd1602.h"
#include "delay.h"
#include "sys.h"
#include "ds18b20.h"
int main(void)
{
short temperature;
u8 ge;
u8 shi;
u8 bai;
u8 qian;
uchar t = 0;
uchar table[] = " 1602 TEST... ";
uchar table1[] = " Successful ! ";
uchar table2[] = " DS18B20 TEST...";
uchar table3[] = "TEMPERATURE IS: ";
delay_init();
lcd_init();
delay_ms(1000);
DS18B20_Init();
lcd162a_WriteCommand(0x80);
for(t = 0;t < 16;t++)
{
lcd162a_WriteData(table[t]);
delay_ms(5);
}
delay_ms(1000);
lcd162a_WriteCommand(0x80+0x40);
for(t = 0;t < 16;t++)
{
lcd162a_WriteData(table1[t]);
delay_ms(5);
}
delay_ms(1000);
lcd162a_WriteCommand(0x01);
for(t = 0;t < 16;t++)
{
lcd162a_WriteData(table2[t]);
delay_ms(5);
}
delay_ms(1000);
lcd162a_WriteCommand(0x80+0x40);
for(t = 0;t < 16;t++)
{
lcd162a_WriteData(table1[t]);
delay_ms(5);
}
delay_ms(1000);
lcd162a_WriteCommand(0x01);
for(t = 0;t < 16;t++)
{
lcd162a_WriteData(table3[t]);
delay_ms(5);
}
while(1)
{
temperature=DS18B20_Get_Temp();
temperature = temperature*10;
qian = temperature /1000;
bai = temperature % 1000 / 100;
shi = temperature % 1000 % 100 / 10;
ge = temperature % 10;
lcd162a_WriteCommand(0x80 + 0x44);
lcd162a_WriteData(0x30+qian);lcd162a_WriteData(0x30+bai);lcd162a_WriteData(0x2e);lcd162a_WriteData(0x30+shi);lcd162a_WriteData(0x30+ge);lcd162a_WriteData(0xdf);lcd162a_WriteData(0x43);
delay_ms(100);
}
}
3、遇到的问题
(1)1602最开始的时候我用的直接就是一个空的工程模板,但是里面的HARDWARE中有一组led.c led.h
这里面也有端口的定义和声明,但是我没有注意到,并且自顾自的编写了1602.h和1602.c里面进行了重复的工作,导致1602一致没有正常工作。所以以后编写STM32程序的时候,需要什么固件库再往里面添加,否则会出现意想不到的问题,也很难查找问题的所在,即便你自己的写的是对的。
(2)在主函数里面temperature=DS18B20_Get_Temp()之后,我认为temperature的值就是XX,X的小数,所以就直接乘以10再分离每一位的数据,导致显示出错。
事实上temperature的值就是XXX 不用将其乘以10再分离每一位的数据,直接分离就好。