这一次做的就是简单的实时显示温度的实验项目,刚开始的时候,在很多论坛看了很多的代码,一昧的堆砌,以为只要Keil不报错就行了,其实在完全不懂的情况下去堆积代码实现自己要的功能就是天方夜谭,所以我花了四天的时间去对stm32进行了简单的学习,知道了怎么初始化GPIO口,怎么利用代码给GPIO口定义,我参考了别人的代码,把很多无关的代码删了,还有一些我认为比较复杂的代码改成了我感觉跟简单能看懂的代码。当然现在的水平还是菜鸟级,但是自己弄的第一个项目成功了还是很开心的,废话不多说,直接先上代码
主要代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "sys.h"
#include "usart.h"
#include "LED.h"
#include "ds18b20.h"
int main(void)
{
uint8_t t = 0;
short temperature;
sys_stm32_clock_init(9);
OLED_Init();
OLED_ShowString(1,1,"Temp: . C");//先在OLED屏幕上显示和温度无关的符号
while (ds18b20_init())
{
Delay_ms(200);
Delay_ms(200);
}
//温度显示和检测
while (1)
{
temperature = ds18b20_get_temperature();
//这里要注意等号后面和你ds18b20.h文件的ds18b20_get_temperature()因为有的人定义的是大写,所以要注意保持一致
OLED_ShowNum(1, 6, temperature/10, 2);
}
Delay_ms(10);
t++;
}
}
在这里我发现最后显示的是只有两位数,就是整数,这样就导致了温度不灵敏并且误差大,之后我对代码进行了修改,使得精度到了0.1,我参考了别人的代码,把温度分成了整数和小数分别来显示。
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "sys.h"
#include "usart.h"
#include "LED.h"
#include "ds18b20.h"
int main(void)
{
uint8_t t = 0;
short temperature;
sys_stm32_clock_init(9);
OLED_Init();
OLED_ShowString(1,1,"Temp: . C");//Temp:共占了5个空,所以温度显示从第六个开始,及第一行第六列,这就是为什么下面都是OLED_ShowNum(1, 6,..)
while (ds18b20_init()) /* DS18B20Եʼۯ */
{
Delay_ms(200);
Delay_ms(200);
}
while (1)
{
if (t % 10 == 0)//如果恰好为10的倍数,直接显示温度
{
temperature = ds18b20_get_temperature();
OLED_ShowNum(1, 6, temperature/10, 2);
}
else//如果不是十的倍数,先显示整数部分,然后显示小数部分
{
OLED_ShowNum(1, 6, temperature/10, 2); //整数部分,保留2位
OLED_ShowNum(1, 9, temperature%10, 1); 除去前面的英文字母,符号,两位整数,所以从第九个开始
}
Delay_ms(10);
t++;
}
}
OLED显示屏代码
#include "stm32f10x.h"
#include "OLED_Font.h"
/*引脚配置*/
#define OLED_W_D0(x) GPIO_WriteBit(GPIOG, GPIO_Pin_13, (BitAction)(x))
#define OLED_W_D1(x) GPIO_WriteBit(GPIOC, GPIO_Pin_0, (BitAction)(x))
#define OLED_W_RES(x) GPIO_WriteBit(GPIOC, GPIO_Pin_2, (BitAction)(x))
#define OLED_W_DC(x) GPIO_WriteBit(GPIOC, GPIO_Pin_4, (BitAction)(x))
#define OLED_W_CS(x) GPIO_WriteBit(GPIOC, GPIO_Pin_6, (BitAction)(x))
/*引脚初始化*/
void OLED_SPI_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOC, &GPIO_InitStructure);
OLED_W_D0(0);
OLED_W_D1(1);
OLED_W_RES(1);
OLED_W_DC(1);
OLED_W_CS(1);
}
/**
* @brief SPI发送一个字节
* @param Byte 要发送的一个字节
* @retval 无
*/
void OLED_SPI_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_D1(Byte & (0x80 >> i));
OLED_W_D0(1);
OLED_W_D0(0);
}
}
/**
* @brief OLED写命令
* @param Command 要写入的命令
* @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_W_CS(0);
OLED_W_DC(0);
OLED_SPI_SendByte(Command);
OLED_W_CS(1);
}
/**
* @brief OLED写数据
* @param Data 要写入的数据
* @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_W_CS(0);
OLED_W_DC(1);
OLED_SPI_SendByte(Data);
OLED_W_CS(1);
}
/**
* @brief OLED设置光标位置
* @param Y 以左上角为原点,向下方向的坐标,范围:0~7
* @param X 以左上角为原点,向右方向的坐标,范围:0~127
* @retval 无
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置高4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置低4位
}
/**
* @brief OLED清屏
* @param 无
* @retval 无
*/
void OLED_Clear(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for(i = 0; i < 128; i++)
{
OLED_WriteData(0x00);
}
}
}
/**
* @brief OLED显示一个字符
* @param Line 行位置,范围:1~4
* @param Column 列位置,范围:1~16
* @param Char 要显示的一个字符,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); //显示上半部分内容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容
}
}
/**
* @brief OLED显示字符串
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++)
{
OLED_ShowChar(Line, Column + i, String[i]);
}
}
/**
* @brief OLED次方函数
* @retval 返回值等于X的Y次方
*/
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}
/**
* @brief OLED显示数字(十进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~4294967295
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十进制,带符号数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-2147483648~2147483647
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
uint8_t i;
uint32_t Number1;
if (Number >= 0)
{
OLED_ShowChar(Line, Column, '+');
Number1 = Number;
}
else
{
OLED_ShowChar(Line, Column, '-');
Number1 = -Number;
}
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十六进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFFFFFF
* @param Length 要显示数字的长度,范围:1~8
* @retval 无
*/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i, SingleNumber;
for (i = 0; i < Length; i++)
{
SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
if (SingleNumber < 10)
{
OLED_ShowChar(Line, Column + i, SingleNumber + '0');
}
else
{
OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
}
}
}
/**
* @brief OLED显示数字(二进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
}
}
/**
* @brief OLED初始化
* @param 无
* @retval 无
*/
void OLED_Init(void)
{
uint32_t i, j;
for (i = 0; i < 1000; i++) //上电延时
{
for (j = 0; j < 1000; j++);
}
OLED_SPI_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); //设置多路复用率
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); //设置显示偏移
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); //设置对比度控制
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); //设置预充电周期
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); //设置VCOMH取消选择级别
OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
OLED_WriteCommand(0xA6); //设置正常/倒转显示
OLED_WriteCommand(0x8D); //设置充电泵
OLED_WriteCommand(0x14);
OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏
}
发温度传感器ds18b20代码g
/**
****************************************************************************************************
* @file ds18b20.c
* @author ֽ֣ԭؓ΅ד(ALIENTEK)
* @version V1.0
* @date 2020-04-26
* @brief DS18B20˽ؖςԫِǷ Ƚ֯պë
* @license Copyright (c) 2020-2032, ڣםːчӭ֧ؓࠆܼԐО٫˾
****************************************************************************************************
* @attention
*
* ʵҩƽ̨:ֽ֣ԭؓ STM32F103ߪעѥ
* ՚П˓Ƶ:www.yuanzige.com
* ܼ˵Û̳:www.openedv.com
* ٫˾θַ:www.alientek.com
* ٺòַ֘:openedv.taobao.com
*
* ўل˵ķ
* V1.0 20200426
* ֚һՎעҼ
*
****************************************************************************************************
*/
#include "Delay.h"
#include "ds18b20.h"
/**
* @brief شλDS18B20
* @param data: Ҫдɫք˽ߝ
* @retval Ϟ
*/
static void ds18b20_reset(void)
{
DS18B20_DQ_OUT(0); /* -֍DQ,شλ */
Delay_us(750); /* -֍750us */
DS18B20_DQ_OUT(1); /* DQ=1, ˍشλ */
Delay_us(15); /* ғԙ15US */
}
/**
* @brief ֈսDS18B20քܘӦ
* @param Ϟ
* @retval 0, DS18B20ֽӣ
* 1, DS18B20Ӭӣ/һզ՚
*/
uint8_t ds18b20_check(void)
{
uint8_t retry = 0;
uint8_t rval = 0;
while (DS18B20_DQ_IN && retry < 200) /* ֈսDQҤ֍, ֈս200us */
{
retry++;
Delay_us(1);
}
if (retry >= 200)
{
rval = 1;
}
else
{
retry = 0;
while (!DS18B20_DQ_IN && retry < 240) /* ֈսDQҤٟ, ֈս240us */
{
retry++;
Delay_us(1);
}
if (retry >= 240) rval = 1;
}
return rval;
}
/**
* @brief ՓDS18B20ׁȡһٶλ
* @param Ϟ
* @retval ׁȡսքλֵ: 0 / 1
*/
static uint8_t ds18b20_read_bit(void)
{
uint8_t data = 0;
DS18B20_DQ_OUT(0);
Delay_us(2);
DS18B20_DQ_OUT(1);
Delay_us(12);
if (DS18B20_DQ_IN)
{
data = 1;
}
Delay_us(50);
return data;
}
/**
* @brief ՓDS18B20ׁȡһٶؖޚ
* @param Ϟ
* @retval ׁսք˽ߝ
*/
static uint8_t ds18b20_read_byte(void)
{
uint8_t i, b, data = 0;
for (i = 0; i < 8; i++)
{
b = ds18b20_read_bit(); /* DS18B20ЈˤԶ֍λ˽ߝ ,ٟλ˽ߝ۳ˤԶ */
data |= b << i; /* ͮԤdataքÿһλ */
}
return data;
}
/**
* @brief дһٶؖޚսDS18B20
* @param data: Ҫдɫքؖޚ
* @retval Ϟ
*/
static void ds18b20_write_byte(uint8_t data)
{
uint8_t j;
for (j = 1; j <= 8; j++)
{
if (data & 0x01)
{
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);
}
data >>= 1; /* Ԓӆ,ܱȡٟһλ˽ߝ */
}
}
/**
* @brief ߪʼςתۻ
* @param Ϟ
* @retval Ϟ
*/
static void ds18b20_start(void)
{
ds18b20_reset();
ds18b20_check();
ds18b20_write_byte(0xcc); /* skip rom */
ds18b20_write_byte(0x44); /* convert */
}
/**
* @brief ԵʼۯDS18B20քIOࠚ DQ ͬʱݬӢDS18B20քզ՚
* @param Ϟ
* @retval 0, ֽӣ
* 1, һզ՚/һֽӣ
*/
uint8_t ds18b20_init(void)
{
DS18B20_DQ_GPIO_CLK_ENABLE(); /* ߪǴDQӽޅʱד */
/* DS18B20_DQӽޅģʽʨ׃,ߪ©ˤԶ,ʏ-, ֢ҹߍһԃՙʨ׃IOв, ߪ©ˤԶքʱ۲(=1), ҲࠉӔׁȡҿхۅքٟ֍֧ƽ */
sys_gpio_set(DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN,
SYS_GPIO_MODE_OUT, SYS_GPIO_OTYPE_OD, SYS_GPIO_SPEED_MID, SYS_GPIO_PUPD_PU);
ds18b20_reset();
return ds18b20_check();
}
/**
* @brief Փds18b20փսςֵ(ޫú0.1C)
* @param Ϟ
* @retval ςֵ è-550~1250é
* @note ܘքςֵճ10Ѷ.
* ʵ݊ʹԃքʱ۲,ҪԽӔ10Ӆˇʵ݊ς.
*/
short ds18b20_get_temperature(void)
{
uint8_t flag = 1; /* ĬɏςΪֽ˽ */
uint8_t TL, TH;
short temp;
ds18b20_start(); /* ds1820 start convert */
ds18b20_reset();
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)
{/* ςΪغìөߴDS18B20քςҭʾרԫ݆̣ܺզԢֽغ˽ߝքԭmһׂú
ֽ˽ҹëΪ݄զǷզԢք˽ߝؔʭìغ˽ҹëΪ݄զǷզԢֵдλȡ״۳+1
̹Ӕϒćֱޓȡ̼ʵ݊քغ˽ҿؖìիغ˽քҹëΪȡ״۳ݓһìիÇս֍λࠉŜ+1۳ԐλۍպëɟԠì
ϒć֢oЈ՝ʱûԐط+1քԦmì֢oѨҪ´Ӣ */
TH = ~TH;
TL = ~TL;
flag = 0; /* ςΪغ */
}
temp = TH; /* ܱփٟыλ */
temp <<= 8;
temp += TL; /* ܱփ֗ыλ */
/* תۻԉʵ݊ς */
if (flag == 0)
{ /* ݫςתۻԉغςì֢oք+1ӎǰĦք˵ķ */
temp = (double)(temp+1) * 0.625;
temp = -temp;
}
else
{
temp = (double)temp * 0.625;
}
return temp;
}