STM32 + ESP32 + FreeRTOS + HAL库实现温湿度、ADC采集:本地打印和云端上传
基于 STM32 + ESP32 开发的环境检测系统,可以实时检测环境温湿度、光照等参数,数据可以通过 OLED 实现本地显示,并支持无线传输功能,可以在云平台 OneNet 上实时显示数据,远距离监视环境的变化。
目录
摘要
基于 STM32 + ESP32 开发的环境检测系统,可以实时检测环境温湿度、光照等参数,数据可以通过 OLED 实现本地显示,并支持无线传输功能,可以在云平台 OneNet 上实时显示数据,远距离监视环境的变化。
一、系统方案
(一)系统功能

(二)系统结构
通过电脑+ST-LINK以及电脑+USB线分别对STM32、ESP32进行供电、烧录和调试,由STM32负责控制,DHT11温湿度传感器负责检测温湿度,ADC负责收集光照等数据,OLED显示屏负责本地打印数据,串口负责将数据发送给ESP32,ESP32将串口接收的数据通过WIFI模块发送到云平台OneNet。
(三)元件选择
1.主控处理器的选择
STM32F103C8T6
STM32凭借低成本优势及成熟的开发生态,在嵌入式系统开发中占据核心地位。ST 官方提供的 HAL 库与标准外设库,通过标准化 API 大幅简化了 GPIO、定时器、通信(UART/SPI/I2C 等)的配置流程,降低开发门槛。该微控制器集成 12 位 ADC、多通道定时器、PWM输出等丰富外设,可无缝对接温湿度传感器、显示模块、电机驱动等设备,覆盖工业控制、智能家居、仪器仪表等多元应用场景。
2.从控处理器的选择
ESP32
ESP32 因其高集成度、低功耗和强大的无线通信能力,在物联网开发领域得到了广泛应用。丰富的开发框架(如 ESP-IDF、Arduino 适配层)使得其编程实现简单高效。该微控制器集成了 Wi-Fi、蓝牙双模通信模块,以及 GPIO、ADC、DAC、UART、SPI、I2C 等多种外设,可轻松对接传感器、显示屏、执行器等外围设备,适用于智能家居、可穿戴设备、工业监测等多种应用场景。由于 ESP32 系列在物联网领域的普及,网络上有海量的技术文档、开源项目和活跃社区,开发者遇到问题时能快速获取解决方案。
3.温湿度检测模块的选择
DHT11
DHT11 是低成本数字温湿度传感器,采用单总线通信,接线极简(仅 3 引脚)。可测 0~50℃(±2℃)、20%~90% RH(±5% RH),适合普通环境监测。
4.ADC采集模块的选择
光敏电阻模块
模拟型光照模块以光敏电阻为核心,利用光电导效应(光照越强电阻越小)将光信号转为模拟电压,需接控制器 ADC 引脚读取。成本低、精度一般,适合楼道照明等简易场景。
热敏电阻模块
模拟型温度模块以热敏电阻为核心,利用热电阻效应(温度越高电阻越小)将温度信号转为模拟电压,需接控制器 ADC 引脚读取。成本低、精度一般,适合室内温度检测等简易场景。
5.显示模块的选择
0.96寸OLED
OLED自发光、高对比度、功耗低,适合小尺寸显示。常用I2C或SPI接口,接线简单,适配主流控制器。支持字符、图形显示,广泛用于便携设备、传感器数据展示等场景。
二、电路设计
(一)电路原理图

(二)实物接线图

三、程序设计
(一)STM32程序设计
1.时钟模块

2.温湿度采集模块
dht11.c
void DHT11_OUT(void )//输出模式
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void DHT11_IN(void )//输入模式
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT ;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void DHT11_REST(void ) //主机发起初始信号
{
DHT11_OUT();
HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, GPIO_PIN_RESET );
delay_ms (20);
HAL_GPIO_WritePin (GPIOA, GPIO_PIN_8, GPIO_PIN_SET );
delay_us (30);
}
uint8_t DHT11_Check(void)
{
uint8_t retry = 0;
DHT11_IN(); // 设置数据引脚为输入模式
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 1 && retry < 80)
{
retry++;
delay_us(1); // 延迟1微秒
}
if (retry >= 80)
return 1; // 如果在规定时间内仍为高电平,表示传感器不响应 返回错误代码1
else
retry = 0;
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0 && retry < 80)
{
retry++;
delay_us(1);
}
if (retry >= 80)
return 1; // 如果在规定时间内仍为高电平,表示传感器不响应 返回错误代码1
return 0; // 传感器响应正常 返回正确代码0
}
//读取一个位
uint8_t DHT11_Read_Bit(void)
{
uint8_t retry=0;
while((HAL_GPIO_ReadPin (GPIOA ,GPIO_PIN_8) == 1 ) && (retry < 100))
{
retry ++;
delay_us (1);
}
retry=0;
while((HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0) && (retry < 100))
{
retry ++;
delay_us (1);
}
delay_us (40);
if(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_8) == 1)
return 1; // 返回读取到的位为高电平
else
return 0; // 返回读取到的位为低电平
}
//读取一个字节
uint8_t DHT11_Read_Byte(void)
{
uint8_t dat=0;
for(uint8_t i=0;i<8;i++)
{
dat <<= 1;
dat |= DHT11_Read_Bit();
}
return dat;
}
//更改数据格式,解码数据
uint8_t DHT11_Read_Data(uint8_t* humi, uint8_t* temp)
{
uint8_t buf[5]; // 储存读取到的五个字节数据到缓冲区
DHT11_REST(); // 初始化传感器通信
if (DHT11_Check() == 0) // 检查传感器是否正常响应
{
for (uint8_t i = 0; i < 5; i++)
buf[i] = DHT11_Read_Byte(); // 逐个字节读取数据
if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]) // 检校验数据的正确性
{
*humi = buf[0]; // 温度值
*temp = buf[2]; // 湿度值
}
}
else
{
return 1; // 传感器响应异常,返回错误代码
}
return 0; // 读取数据正确,返回正常代码
}
注意:温度模块需要配合延时模块使用 !!!
3.延时模块
delay.c
void delay_us(uint16_t nus)
{
__HAL_TIM_SET_COUNTER(&htim1, 0);
__HAL_TIM_ENABLE(&htim1);
while (__HAL_TIM_GET_COUNTER(&htim1) < nus)
{
}
__HAL_TIM_DISABLE(&htim1);
}
void delay_ms(uint32_t nms)
{
// 分块处理,每次最多处延时65ms(避免16位计数器溢出)
while (nms > 65) {
delay_us(65000); // 延时65ms
nms -= 65;
}
// 处理剩余毫秒数
delay_us(nms * 1000);
}
注意:延时模块需要配合定时器使用 !!!
4.定时器模块
TIM1的配置
5.OLED显示模块
oled.c
/**********************************************************
* 初始化命令,根据芯片手册书写,详细步骤见上图以及注意事项
***********************************************************/
uint8_t CMD_Data[]={
0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00, 0x40,0xA1, 0xC8, 0xDA,
0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x40, 0xA4, 0xA6,0x8D, 0x14,
0xAF};
/**
* @function: void OLED_Init(void)
* @description: OLED初始化
* @return {*}
*/
void OLED_Init(void)
{
HAL_Delay(200);
uint8_t i = 0;
for(i=0; i<23; i++)
{
OLED_WR_CMD(CMD_Data[i]);
}
}
/**
* @function: void OLED_WR_CMD(uint8_t cmd)
* @description: 向设备写控制命令
* @param {uint8_t} cmd 芯片手册规定的命令
* @return {*}
*/
void OLED_WR_CMD(uint8_t cmd)
{
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}
/**
* @function: void OLED_WR_DATA(uint8_t data)
* @description: 向设备写控制数据
* @param {uint8_t} data 数据
* @return {*}
*/
void OLED_WR_DATA(uint8_t data)
{
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);
}
/**
* @function: void OLED_On(void)
* @description: 更新显示
* @return {*}
*/
void OLED_On(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
OLED_WR_CMD(0xb0+i); //设置页地址(0~7)
OLED_WR_CMD(0x00); //设置显示位置—列低地址
OLED_WR_CMD(0x10); //设置显示位置—列高地址
for(n=0;n<128;n++)
OLED_WR_DATA(1);
}
}
/**
* @function: OLED_Clear(void)
* @description: 清屏,整个屏幕是黑色的!和没点亮一样!!!
* @return {*}
*/
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
OLED_WR_CMD(0xb0+i); //设置页地址(0~7)
OLED_WR_CMD(0x00); //设置显示位置—列低地址
OLED_WR_CMD(0x10); //设置显示位置—列高地址
for(n=0;n<128;n++)
OLED_WR_DATA(0);
}
}
/**
* @function: void OLED_Display_On(void)
* @description: 开启OLED显示
* @return {*}
*/
void OLED_Display_On(void)
{
OLED_WR_CMD(0X8D); //SET DCDC命令
OLED_WR_CMD(0X14); //DCDC ON
OLED_WR_CMD(0XAF); //DISPLAY ON,打开显示
}
/**
* @function: void OLED_Display_Off(void)
* @description: 关闭OLED显示
* @return {*}
*/
void OLED_Display_Off(void)
{
OLED_WR_CMD(0X8D); //SET DCDC命令
OLED_WR_CMD(0X10); //DCDC OFF
OLED_WR_CMD(0XAE); //DISPLAY OFF,关闭显示
}
/**
* @function: void OLED_Set_Pos(uint8_t x, uint8_t y)
* @description: 坐标设置
* @param {uint8_t} x,y
* @return {*}
*/
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
OLED_WR_CMD(0xb0+y); //设置页地址(0~7)
OLED_WR_CMD(((x&0xf0)>>4)|0x10); //设置显示位置—列高地址
OLED_WR_CMD(x&0x0f); //设置显示位置—列低地址
}
/**
* @function: unsigned int oled_pow(uint8_t m,uint8_t n)
* @description: m^n函数
* @param {uint8_t} m,n
* @return {unsigned int} result
*/
unsigned int oled_pow(uint8_t m,uint8_t n)
{
unsigned int result=1;
while(n--)result*=m;
return result;
}
/**
* @function: void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size,uint8_t Color_Turn)
* @description: 在OLED12864特定位置开始显示一个字符
* @param {uint8_t} x字符开始显示的横坐标
* @param {uint8_t} y字符开始显示的纵坐标
* @param {uint8_t} chr待显示的字符
* @param {uint8_t} Char_Size待显示字符的字体大小,选择字体 16/12
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size,uint8_t Color_Turn)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>128-1){x=0;y=y+2;}
if(Char_Size ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
{
if(Color_Turn)
OLED_WR_DATA(~F8X16[c*16+i]);
else
OLED_WR_DATA(F8X16[c*16+i]);
}
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
{
if(Color_Turn)
OLED_WR_DATA(~F8X16[c*16+i+8]);
else
OLED_WR_DATA(F8X16[c*16+i+8]);
}
}
else
{
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
{
if(Color_Turn)
OLED_WR_DATA(~F6x8[c][i]);
else
OLED_WR_DATA(F6x8[c][i]);
}
}
}
/**
* @function: void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_tChar_Size, uint8_t Color_Turn)
* @description: 在OLED12864特定位置开始显示字符串
* @param {uint8_t} x待显示字符串的开始横坐标x:0~127
* @param {uint8_t} y待显示字符串的开始纵坐标 y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
* @param {uint8_t} *chr待显示的字符串
* @param {uint8_t} Char_Size待显示字符串的字体大小,选择字体 16/12,16为8X16,12为6x8
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowString(uint8_t x,uint8_t y,char*chr,uint8_t Char_Size, uint8_t Color_Turn)
{
uint8_t j=0;
while (chr[j]!='\0')
{ OLED_ShowChar(x,y,chr[j],Char_Size, Color_Turn);
if (Char_Size == 12) //6X8的字体列加6,显示下一个字符
x += 6;
else //8X16的字体列加8,显示下一个字符
x += 8;
if (x > 122 && Char_Size==12) //TextSize6x8如果一行不够显示了,从下一行继续显示
{
x = 0;
y++;
}
if (x > 120 && Char_Size== 16) //TextSize8x16如果一行不够显示了,从下一行继续显示
{
x = 0;
y++;
}
j++;
}
}
/**
* @function: void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2, Color_Turn)
* @description: 显示数字
* @param {uint8_t} x待显示的数字起始横坐标,x:0~126
* @param {uint8_t} y待显示的数字起始纵坐标, y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
* @param {unsigned int} num:输入的数据
* @param {uint8_t } len:输入的数据位数
* @param {uint8_t} size2:输入的数据大小,选择 16/12,16为8X16,12为6x8
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2, uint8_t Color_Turn)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2, Color_Turn);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2, Color_Turn);
}
}
/**
* @function: void OLED_Showdecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn)
* @description: 显示正负浮点数
* @param {uint8_t} x待显示的数字起始横坐标,x:0~126
* @param {uint8_t} y待显示的数字起始纵坐标, y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
* @param {float} num:输入的浮点型数据
* @param {uint8_t } z_ len:整数部分的位数
* @param {uint8_t } f_len: 小数部分的位数
* @param {uint8_t} size2:输入的数据大小,选择 16/12,16为8X16,12为6x8
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_Showdecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn)
{
uint8_t t,temp,i=0;//i为负数标志位
uint8_t enshow;
int z_temp,f_temp;
if(num<0)
{
z_len+=1;
i=1;
num=-num;
}
z_temp=(int)num;
//整数部分
for(t=0;t<z_len;t++)
{
temp=(z_temp/oled_pow(10,z_len-t-1))%10;
if(enshow==0 && t<(z_len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2, Color_Turn);
continue;
}
else
enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2, Color_Turn);
}
//小数点
OLED_ShowChar(x+(size2/2)*(z_len),y,'.',size2, Color_Turn);
f_temp=(int)((num-z_temp)*(oled_pow(10,f_len)));
//小数部分
for(t=0;t<f_len;t++)
{
temp=(f_temp/oled_pow(10,f_len-t-1))%10;
OLED_ShowChar(x+(size2/2)*(t+z_len)+5,y,temp+'0',size2, Color_Turn);
}
if(i==1)//如果为负,就将最前的一位赋值‘-’
{
OLED_ShowChar(x,y,'-',size2, Color_Turn);
i=0;
}
}
/**
* @function: void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn)
* @description: 在OLED特定位置开始显示16X16汉字
* @param {uint8_t} x待显示的汉字起始横坐标x: 0~112,两列汉字之间需要间隔16
* @param {uint8_t} y待显示的汉字起始纵坐标 y: 0~6 , 两行汉字之间需要间隔2
* @param {uint8_t} no待显示的汉字编号
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn)
{
uint8_t t=0;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)
{
if (Color_Turn)
OLED_WR_DATA(~Hzk[2*no][t]); //显示汉字的上半部分
else
OLED_WR_DATA(Hzk[2*no][t]); //显示汉字的上半部分
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
if (Color_Turn)
OLED_WR_DATA(~Hzk[2*no+1][t]); //显示汉字的上半部分
else
OLED_WR_DATA(Hzk[2*no+1][t]);//显示汉字的上半部分
}
}
/**
* @function: void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t * BMP,uint8_t Color_Turn)
* @description: 在OLED特定区域显示BMP图片
* @param {uint8_t} x0图像开始显示横坐标 x0:0~127
* @param {uint8_t} y0图像开始显示纵坐标 y0:0~7
* @param {uint8_t} x1图像结束显示横坐标 x1:1~128
* @param {uint8_t} y1图像结束显示纵坐标 y1:1~8
* @param {uint8_t} *BMP待显示的图像数据
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t * BMP,uint8_t Color_Turn)
{
uint32_t j = 0;
uint8_t x = 0, y = 0;
if(y1%8==0)
y = y1/8;
else
y = y1/8 + 1;
for(y=y0;y<y1;y++)
{
OLED_Set_Pos(x0,y);
for(x=x0;x<x1;x++)
{
if (Color_Turn)
OLED_WR_DATA(~BMP[j++]);//显示反相图片
else
OLED_WR_DATA(BMP[j++]);//显示图片
}
}
}
/**
* @function: void OLED_HorizontalShift(uint8_t direction)
* @description: 屏幕内容水平全屏滚动播放
* @param {uint8_t} direction LEFT 0x27 RIGHT 0x26
* @return {*}
*/
void OLED_HorizontalShift(uint8_t direction)
{
OLED_WR_CMD(0x2e);//停止滚动
OLED_WR_CMD(direction);//设置滚动方向
OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
OLED_WR_CMD(0x00);//设置开始页地址
OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频
// 0x00-5帧, 0x01-64帧, 0x02-128帧, 0x03-256帧, 0x04-3帧, 0x05-4帧, 0x06-25帧, 0x07-2帧,
OLED_WR_CMD(0x07);//设置结束页地址
OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}
/**
* @function: void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end)
* @description: 屏幕部分内容水平滚动播放
* @param {uint8_t} direction LEFT 0x27 RIGHT 0x26
* @param {uint8_t} start 开始页地址 0x00~0x07
* @param {uint8_t} end 结束页地址 0x01~0x07
* @return {*}
*/
void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end)
{
OLED_WR_CMD(0x2e);//停止滚动
OLED_WR_CMD(direction);//设置滚动方向
OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
OLED_WR_CMD(start);//设置开始页地址
OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频,0x07即滚动速度2帧
OLED_WR_CMD(end);//设置结束页地址
OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}
/**
* @function: void OLED_VerticalAndHorizontalShift(uint8_t direction)
* @description: 屏幕内容垂直水平全屏滚动播放
* @param {uint8_t} direction 右上滚动 0x29
* 左上滚动 0x2A
* @return {*}
*/
void OLED_VerticalAndHorizontalShift(uint8_t direction)
{
OLED_WR_CMD(0x2e);//停止滚动
OLED_WR_CMD(direction);//设置滚动方向
OLED_WR_CMD(0x01);//虚拟字节设置
OLED_WR_CMD(0x00);//设置开始页地址
OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频,即滚动速度
OLED_WR_CMD(0x07);//设置结束页地址
OLED_WR_CMD(0x01);//垂直滚动偏移量
OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}
/**
* @function: void OLED_DisplayMode(uint8_t mode)
* @description: 屏幕内容取反显示
* @param {uint8_t} direction ON 0xA7 ,
* OFF 0xA6 默认此模式,设置像素点亮
* @return {*}
*/
void OLED_DisplayMode(uint8_t mode)
{
OLED_WR_CMD(mode);
}
/**
* @function: void OLED_IntensityControl(uint8_t intensity)
* @description: 屏幕亮度调节
* @param {uint8_t} intensity 0x00~0xFF,RESET=0x7F
* @return {*}
*/
void OLED_IntensityControl(uint8_t intensity)
{
OLED_WR_CMD(0x81);
OLED_WR_CMD(intensity);
}
oled_font.c
//8*6 ASCII字符集点阵
const unsigned char F6x8[][6] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// sp
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,// #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,// $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23,// %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50,// &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00,// '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,// (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,// )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,// *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,// +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,// ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08,// -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00,// .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02,// /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,// 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46,// 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,// 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,// 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39,// 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03,// 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36,// 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,// 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00,// :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00,// ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00,// <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14,// =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08,// >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06,// ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,// @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,// A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,// B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,// C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,// D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,// E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,// F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,// G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,// H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,// I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,// J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,// K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,// L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,// M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,// N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,// O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,// P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,// R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31,// S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,// T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,// U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,// V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,// W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63,// X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07,// Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43,// Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,// [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,// 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,// ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04,// ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40,// _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00,// '
0x00, 0x20, 0x54, 0x54, 0x54, 0x78,// a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,// b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20,// c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,// d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18,// e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,// f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,// g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,// h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,// i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,// j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,// k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,// l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,// m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,// n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38,// o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,// p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,// q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,// r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20,// s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,// t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,// u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,// v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,// w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44,// x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,// y
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,// z
0x14, 0x14, 0x14, 0x14, 0x14, 0x14,// horiz lines
};
//16*8 ASCII集点阵
const unsigned char F8X16[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//sp /0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! /1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" /2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# /3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ /4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% /5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& /6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' /7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( /8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) /9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* /10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ /11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, /12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- /13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. /14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// /15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 /16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 /17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 /18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 /19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 /20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 /21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 /22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 /23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 /24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 /25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: /26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; /27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< /28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= /29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> /30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? /31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ /32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A /33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B /34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C /35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D /36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E /37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F /38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G /39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H /40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I /41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J /42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K /43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L /44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M /45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N /46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O /47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P /48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q /49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R /50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S /51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T /52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U /53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V /54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W /55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X /56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y /57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z /58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ /59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ /60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] /61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ /62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ /63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` /64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a /65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b /66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c /67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d /68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e /69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f /70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g /71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h /72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i /73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j /74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k /75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l /76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m /77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n /78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o /79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p /80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q /81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r /82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s /83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t /84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u /85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v /86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w /87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x /88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y /89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z /90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ /91
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} /92
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00};//| /93
//部分汉字 阴码,列行式,逆向
const unsigned char Hzk[][32]=
{
{0x40,0x22,0x14,0x08,0xF4,0x02,0x00,0xF8,0x08,0x08,0xFF,0x08,0x08,0xF8,0x00,0x00},
{0x08,0x44,0x82,0x41,0x3F,0x00,0x20,0x63,0x21,0x21,0x3F,0x21,0x29,0x33,0x60,0x00},/*"?",0*/
{0x20,0x10,0xE8,0x24,0x27,0x24,0x24,0xE4,0x24,0x34,0x2C,0x20,0xE0,0x00,0x00,0x00},
{0x80,0x60,0x1F,0x09,0x09,0x09,0x09,0x7F,0x09,0x09,0x49,0x89,0x7F,0x00,0x00,0x00},/*"?",1*/
{0x00,0x00,0x7C,0x54,0x55,0x56,0x54,0x7C,0x54,0x56,0x55,0x54,0x7C,0x00,0x00,0x00},
{0x01,0x01,0x01,0xFD,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0xFD,0x01,0x01,0x01,0x00},/*"?",2*/
};
//128*64图片
unsigned char BMP1[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x40,0xE0,0xE0,0x60,
0x00,0x40,0x80,0x00,0x00,0x00,0x80,0x80,0x60,0x60,0x10,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x90,0xB2,0x66,0x6E,0xEC,0xC9,0x83,0x02,0x00,0x40,0x80,
0x00,0x0C,0x0C,0x01,0x03,0x07,0x0F,0x11,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x08,0x18,0x3B,0x37,0x66,0xEE,0xEE,0xCC,0x88,0x80,0x00,0x00,
0x01,0x02,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x0F,0x00,0x00,0x00,0x00,0x00,
0x00,0x3E,0x40,0x40,0x40,0x3E,0x00,0x7E,0x04,0x08,0x10,0x7E,0x00,0x7E,0x00,0x3C,
0x42,0x42,0x42,0x42,0x00,0x7E,0x42,0x42,0x42,0x7E,0x00,0x7E,0x04,0x08,0x10,0x7E,/*"C:\Users\HP\Desktop\UNICORN.BMP",0*/
};
注意:OLED模块要配合I2C使用!!!
6.I2C模块
I2C1配置

注意:不用开启全局中断!!!
7.ADC采集模块
ADC1配置

注意:要开启ADC1的DMA全局中断 !!!
8.USART模块
USART1配置

注意:要开启USART1的全局中断 !!!
USART3配置

注意:要开启USART3的DMA全局中断 !!!
9.调试模块
printf函数重定义
/*********************************************
printf()重定义
*********************************************/
/* 禁用半主机模式 */
#pragma import(__use_no_semihosting)
/* 标准库需要的支持函数 */
struct __FILE
{
int handle;
};
FILE __stdout;
/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x) {
x = x;
}
/* 重定义fput函数,将printf输出定向到USART1 */
int fputc(int ch, FILE *f) {
uint8_t c = (uint8_t)ch;
HAL_UART_Transmit(&huart1, &c, 1, 100); // 通过USART1发送字符
return ch;
}
注意:调试模块配合USART1使用!!! 这段代码一般放在usart.c里
10.操作系统模块
freertos配置


说明:1.创建了五个任务,优先级从大到小依次为ADC、DHT11、OLED、WiFi、default
2.创建了互斥量
注意:使用CMSIS-V1!!!
11.FreeRTOS模块
freertos.c
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "adc.h"
#include "dht11.h"
#include "oled.h"
#include "stdio.h"
#include "string.h"
#include "detection.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
SensorData g_sensorData; //传感器数据
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
osThreadId defaultTaskHandle;
osThreadId OLEDHandle;
osThreadId ADCHandle;
osThreadId DHT11Handle;
osThreadId WiFiHandle;
osMutexId SensorMutexHandle;
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void const * argument);
void OLED_Task(void const * argument);
void ADC_Task(void const * argument);
void DHT11_Task(void const * argument);
void WiFi_Task(void const * argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Create the mutex(es) */
/* definition and creation of SensorMutex */
osMutexDef(SensorMutex);
SensorMutexHandle = osMutexCreate(osMutex(SensorMutex));
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* definition and creation of defaultTask */
osThreadDef(defaultTask, StartDefaultTask, osPriorityLow, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
/* definition and creation of OLED */
osThreadDef(OLED, OLED_Task, osPriorityNormal, 0, 128);
OLEDHandle = osThreadCreate(osThread(OLED), NULL);
/* definition and creation of ADC */
osThreadDef(ADC, ADC_Task, osPriorityHigh, 0, 128);
ADCHandle = osThreadCreate(osThread(ADC), NULL);
/* definition and creation of DHT11 */
osThreadDef(DHT11, DHT11_Task, osPriorityAboveNormal, 0, 128);
DHT11Handle = osThreadCreate(osThread(DHT11), NULL);
/* definition and creation of WiFi */
osThreadDef(WiFi, WiFi_Task, osPriorityBelowNormal, 0, 128);
WiFiHandle = osThreadCreate(osThread(WiFi), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转PC13(板载LED)电平
osDelay(400);
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE BEGIN Header_OLED_Task */
/**
* @brief Function implementing the OLED thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_OLED_Task */
void OLED_Task(void const * argument)
{
/* USER CODE BEGIN OLED_Task */
SensorData oleddata;
OLED_ShowString(4, 2, "humidity:", 12, 0);
OLED_ShowString(4, 3, "temperature:", 12, 0);
OLED_ShowString(4, 5, "thermistor:", 12, 0);
OLED_ShowString(4, 6, "photoresistor:", 12, 0);
/* Infinite loop */
for(;;)
{
osMutexWait(SensorMutexHandle, osWaitForever);
oleddata = g_sensorData; // 拷贝全局数据到本地
osMutexRelease(SensorMutexHandle);
OLED_ShowNum(112, 2, oleddata.humidity, 2, 12, 0); // 显示湿度(湿度范围0-99)
OLED_ShowNum(112, 3, oleddata.temperature, 2, 12, 0); // 显示温度(温度范围0-99)
OLED_ShowNum(100, 5, oleddata.thermistor, 4, 12, 0); // 显示热敏电阻的ADC值(0-4095)
OLED_ShowNum(100, 6, oleddata.photoresistor, 4, 12, 0); // 显示光敏电阻的ADC值(0-4095)
osDelay(500);
}
/* USER CODE END OLED_Task */
}
/* USER CODE BEGIN Header_ADC_Task */
/**
* @brief Function implementing the ADC thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_ADC_Task */
void ADC_Task(void const * argument)
{
/* USER CODE BEGIN ADC_Task */
/* Infinite loop */
for(;;)
{
osMutexWait(SensorMutexHandle, osWaitForever);
g_sensorData.thermistor = adcDmaBuffer[0];
g_sensorData.photoresistor = adcDmaBuffer[1];
osMutexRelease(SensorMutexHandle);
//printf("adc_val:%4d\t illuminance:%4d\r\n", g_sensorData.adc_val, g_sensorData.illuminance);
osDelay(100);
}
/* USER CODE END ADC_Task */
}
/* USER CODE BEGIN Header_DHT11_Task */
/**
* @brief Function implementing the DHT11 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_DHT11_Task */
void DHT11_Task(void const * argument)
{
/* USER CODE BEGIN DHT11_Task */
/* Infinite loop */
for(;;)
{
uint8_t humidity, temperature;
DHT11_Read_Data(&humidity, &temperature); // 读取DHT11
osMutexWait(SensorMutexHandle, osWaitForever);
g_sensorData.humidity = humidity;
g_sensorData.temperature = temperature;
osMutexRelease(SensorMutexHandle);
//printf("humidity:%2d\t illuminance:%2d\r\n", g_sensorData.humidity, g_sensorData.temperature);
osDelay(2000); // DHT11 采集至少2s
}
/* USER CODE END DHT11_Task */
}
/* USER CODE BEGIN Header_WiFi_Task */
/**
* @brief Function implementing the WiFi thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_WiFi_Task */
void WiFi_Task(void const * argument)
{
/* USER CODE BEGIN WiFi_Task */
SensorData wifidata;
/* Infinite loop */
for(;;)
{
osMutexWait(SensorMutexHandle, osWaitForever);
wifidata = g_sensorData; // 拷贝全局数据到本地
osMutexRelease(SensorMutexHandle);
wifidata.head = 0xAA;
wifidata.tail = 0x55;
memcpy(esp32TxBuffer, &wifidata, ESP32_TX_BUF_SIZE);
//测试
// printf("adc_val:%4d illuminance:%4d temperature:%2d humidity:%2d\r\n",
// wifidata.thermistor, wifidata.photoresistor, wifidata.temperature, wifidata.humidity);
for(int i =0; i < ESP32_TX_BUF_SIZE; i++)
{
printf("%02X", esp32TxBuffer[i]);
}
printf("\r\n");
osDelay(10);
}
/* USER CODE END WiFi_Task */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
说明:通过互斥量,保证多个线程对全局变量的互斥访问,避免数据竞争,保证数据一致性。
12.DMA开启和硬件检测模块
detection.c
// 创建 ADC+DMA 缓冲区
uint16_t adcDmaBuffer[ADC_DMA_BUFFER_SIZE];
// 创建串口发送缓冲区
uint8_t esp32TxBuffer[ESP32_TX_BUF_SIZE];
void detection(void)
{
// 校验 ADC
while(HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
{
printf("ADC Calibration Failed!\r\n");
HAL_Delay(100);
}
printf("ADC Calibration Success!\r\n");
// 开启 ADC+DMA 转运
while(HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adcDmaBuffer, ADC_DMA_BUFFER_SIZE) != HAL_OK)
{
printf("ADC DMA Start Error!\r\n");
HAL_Delay(100);
}
printf("ADC DMA Start Success!\r\n");
// 开启 USART3+DMA 传输
while(HAL_UART_Transmit_DMA(&huart3, (uint8_t *)esp32TxBuffer, ESP32_TX_BUF_SIZE)!= HAL_OK)
{
printf("USART3 DMA Transmit Error!\r\n");
HAL_Delay(100);
}
printf("USART3 DMA Transmit Success!\r\n");
// 检测 DHT11 连接
while(DHT11_Check() == 0)
{
printf("DHT11 Connection Failed!\r\n");
HAL_Delay(100);
}
printf("DHT11 Connection Success !\r\n");
}
说明:因为USART3和ADC1都开启了DMA循环模式,所以只需要启动一次
detection.h
#ifndef DETECTION_H_
#define DETECTION_H_
#include "main.h"
#include "stdio.h"
#include "dht11.h"
extern ADC_HandleTypeDef hadc1;
extern UART_HandleTypeDef huart3;
#pragma pack(1)
typedef struct {
uint8_t head;
uint16_t thermistor;
uint16_t photoresistor;
uint8_t temperature;
uint8_t humidity;
uint8_t tail;
} SensorData;
#pragma pack()
#define ADC_DMA_BUFFER_SIZE 32
extern uint16_t adcDmaBuffer[ADC_DMA_BUFFER_SIZE];
#define ESP32_TX_BUF_SIZE sizeof(SensorData)
extern uint8_t esp32TxBuffer[ESP32_TX_BUF_SIZE];
void detection(void);
#endif
13.注意事项
1.通过串口发送的是结构体的二进制数据,增加了帧头帧尾,方便接收端的数据解析
2.一定要控制串口发送缓冲区的大小取决于结构体的大小
(二)ESP32程序设计
1.程序代码
#include <Arduino.h>
#include "WiFi.h"
#include "PubSubClient.h"
#include "ArduinoJson.h"
#include <HardwareSerial.h>
// 与STM32完全一致的结构体定义
#pragma pack(1)
typedef struct {
uint8_t head;
uint16_t thermistor; // uint16_t类型(2字节)
uint16_t photoresistor; // uint16_t类型(2字节)
uint8_t temperature; // uint8_t类型(1字节)
uint8_t humidity; // uint8_t类型(1字节)
uint8_t tail;
} SensorData;
#pragma pack()
// 全局变量:存储解析成功的传感器数据
SensorData parsedSensorData;
bool hasValidData = false; // 标记是否有有效数据(避免上传空值)
#define SENSOR_DATA_LEN sizeof(SensorData)
#define RX_BUFFER_SIZE 128 // 接收缓冲区大小
uint8_t rx_buffer[RX_BUFFER_SIZE]; // 接收缓冲区
size_t rx_len = 0; // 缓冲区数据长度
// WiFi和MQTT配置
const char* ssid = "vivo X23"; //wifi名
const char* password = "123456789"; //wifi密码
const char* mqtt_server = "mqtts.heclouds.com"; //onenet 的 IP地址 mqtts.heclouds.com 183.230.40.96
const int port = 1883; //端口号
#define mqtt_pubid "899v38taqa" //产品ID
#define mqtt_devid "ESP32" //设备名称
#define mqtt_password "version=2018-10-31&res=products%2F899v38taqa%2Fdevices%2FESP32&et=1911074531&method=md5&sign=5pHVGmmr3GiSN%2BGbBVekWQ%3D%3D" //鉴权信息
WiFiClient espClient;
PubSubClient client(espClient);
// MQTT主题
#define ONENET_TOPIC_PROP_POST "$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/post"
#define ONENET_TOPIC_PROP_SET "$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/set"
#define ONENET_TOPIC_PROP_SET_REPLY "$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/set_reply"
#define ONENET_TOPIC_PROP_GET "$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/get"
#define ONENET_TOPIC_PROP_GET_REPLY "$sys/" mqtt_pubid "/" mqtt_devid "/thing/property/get_reply"
// JSON格式宏
// %hu:匹配uint16_t(adc_val/illuminance);%hhu:匹配uint8_t(temperature/humidity)
#define PARAMS_FORMAT "{\"thermistor\": {\"value\": %hu}, \"photoresistor\": {\"value\": %hu}, \"temperature\": {\"value\": %hhu}, \"humidity\": {\"value\": %hhu}}"
#define FULL_FORMAT "{\"id\": \"123\", \"version\": \"1.0\", \"params\": %s}"
// 连接WiFi
void setupWifi() {
delay(10);
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (!WiFi.isConnected()) {
Serial.print(".");
delay(500);
}
Serial.println("\nWiFi connected!");
Serial.println("IP address: " + WiFi.localIP().toString());
}
// MQTT重连
void clientReconnect() {
while (!client.connected()) {
Serial.println("Reconnecting to MQTT...");
if (client.connect(mqtt_devid, mqtt_pubid, mqtt_password)) {
Serial.println("MQTT connected");
client.subscribe(ONENET_TOPIC_PROP_SET);
client.subscribe(ONENET_TOPIC_PROP_GET);
} else {
Serial.print("Failed, state: ");
Serial.println(client.state());
delay(5000);
}
}
}
// // MQTT回调(可拓展)
// void callback(char *topic, byte *payload, unsigned int length) {
// Serial.println("Received message:");
// Serial.println(topic);
// for (size_t i = 0; i < length; i++) {
// Serial.print((char)payload[i]);
// }
// Serial.println();
// if (strstr(topic, ONENET_TOPIC_PROP_SET)) {
// DynamicJsonDocument doc(100);
// DeserializationError error = deserializeJson(doc, payload);
// if (error) {
// Serial.println("Parse JSON failed");
// return;
// }
// String id = doc["id"].as<String>();
// char reply[100];
// sprintf(reply, "{\"id\": \"%s\",\"code\":200,\"msg\":\"success\"}", id.c_str());
// client.publish(ONENET_TOPIC_PROP_SET_REPLY, reply);
// }
// if (strstr(topic, ONENET_TOPIC_PROP_GET)) {
// DynamicJsonDocument doc(100);
// DeserializationError error = deserializeJson(doc, payload);
// if (error) {
// Serial.println("Parse JSON failed");
// return;
// }
// String id = doc["id"].as<String>();
// char reply[200];
// // 若有有效数据,回复当前传感器值
// if (hasValidData) {
// sprintf(reply, "{\"id\": \"%s\",\"code\":200,\"data\":{\"adc_val\":%hu,\"illuminance\":%hu,\"temperature\":%hhu,\"humidity\":%hhu}}",
// id.c_str(), parsedSensorData.thermistor, parsedSensorData.photoresistor,
// parsedSensorData.temperature, parsedSensorData.humidity);
// } else {
// sprintf(reply, "{\"id\": \"%s\",\"code\":400,\"msg\":\"no data\"}", id.c_str());
// }
// client.publish(ONENET_TOPIC_PROP_GET_REPLY, reply);
// }
// }
// 解析传感器数据
void parse_sensor_data(void) {
for (size_t i = 0; i <= rx_len - SENSOR_DATA_LEN; i++) {
// 检测帧头(0xAA)和帧尾(0x55)
if (rx_buffer[i] == 0xAA && rx_buffer[i + SENSOR_DATA_LEN - 1] == 0x55) {
// 将解析到的数据复制到全局变量
memcpy(&parsedSensorData, &rx_buffer[i], SENSOR_DATA_LEN);
hasValidData = true; // 标记有有效数据
// 打印解析结果(调试)
// Serial.print("解析成功:");
// Serial.print("热敏传感器=");
// Serial.print(parsedSensorData.thermistor);
// Serial.print(",光敏传感器=");
// Serial.print(parsedSensorData.photoresistor);
// Serial.print(",温度=");
// Serial.print(parsedSensorData.temperature);
// Serial.print("℃,湿度=");
// Serial.print(parsedSensorData.humidity);
// Serial.println("%");
// 移除已解析数据,保留剩余内容
memmove(rx_buffer, rx_buffer + i + SENSOR_DATA_LEN, rx_len - (i + SENSOR_DATA_LEN));
rx_len -= (i + SENSOR_DATA_LEN);
return;
}
}
// 缓冲区快满时重置
if (rx_len > RX_BUFFER_SIZE * 0.8) {
rx_len = 0;
Serial.println("未找到完整数据包,缓冲区已重置");
}
}
// 读取串口数据
void read_sensor_data(void) {
while (Serial2.available() > 0 && rx_len < RX_BUFFER_SIZE) {
rx_buffer[rx_len++] = Serial2.read();
}
if (rx_len >= SENSOR_DATA_LEN) {
parse_sensor_data();
}
}
// 上传数据到云端
void sendtocloud(void) {
if (client.connected() && hasValidData) { // 仅当有有效数据时上传
char params_str[128] = {0};
char full_json[256] = {0};
// 用全局变量中的解析数据填充params
sprintf(params_str, PARAMS_FORMAT,
parsedSensorData.thermistor, // 使用解析后的ADC值
parsedSensorData.photoresistor, // 使用解析后的光照度
parsedSensorData.temperature, // 使用解析后的温度
parsedSensorData.humidity); // 使用解析后的湿度
// 组装完整JSON
sprintf(full_json, FULL_FORMAT, params_str);
// 发布到云端
if (client.publish(ONENET_TOPIC_PROP_POST, full_json)) {
Serial.print("上传成功:");
Serial.println(full_json);
} else {
Serial.println("上传失败!");
}
} else if (!hasValidData) {
Serial.println("无有效数据,暂不上传");
}
}
void setup() {
Serial.begin(115200);
Serial2.begin(115200, SERIAL_8N1, 16, 17); // 初始化串口2(接STM32)
delay(3000);
setupWifi();
client.setServer(mqtt_server, port);
//client.setCallback(callback); (可拓展)
delay(2000);
clientReconnect(); // 连接MQTT
}
void loop() {
if (!WiFi.isConnected()) {
setupWifi();
}
if (!client.connected()) {
clientReconnect();
}
client.loop();
read_sensor_data(); // 持续读取并解析STM32数据
sendtocloud(); //上传数据到云端
}
2.代码说明
// WiFi和MQTT配置
const char* ssid = "vivo X23"; //wifi名
const char* password = "123456789"; //wifi密码
#define mqtt_pubid "899v38taqa" //产品ID
#define mqtt_devid "ESP32" //设备名称
#define mqtt_password "version=2018-10-31&res=products%2F899v38taqa%2Fdevices%2FESP32&et=1911074531&method=md5&sign=5pHVGmmr3GiSN%2BGbBVekWQ%3D%3D" //鉴权信息
#define PARAMS_FORMAT "{\"thermistor\": {\"value\": %hu}, \"photoresistor\": {\"value\": %hu}, \"temperature\": {\"value\": %hhu}, \"humidity\": {\"value\": %hhu}}"
说明:上述内容需要修改,详细内容查看文章ESP32连接OneNet
四、测试结果
(一)STM32测试
1.OLED打印

2.串口发送数据

(二)ESP32测试
1.上传数据

2.云端显示

五、参考文章
1.文章框架:stm32+DHT11温湿度检测系统_dht11stm32温度检测系统框架-CSDN博客
2.温湿度采集: 【STM32(HAL库)--DHT11温湿度传感器】_stm32 dh11库函数-CSDN博客
3.OLED显示: 4针0.96寸OLED的HAL库代码(硬件I2C/全代码/stm32f1/CubeMX配置/包含有正负浮点数/100%一次点亮)_hal库4针oled-CSDN博客
4.ESP32连接OneNet:【手把手教你用ESP32连接MQTT云端!!】https://www.bilibili.com/video/BV14ZuBz8E9x?vd_source=5fefab38f2696a32ccef96a4db3b4eea
更多推荐



所有评论(0)