- 2025-03-23
-
发表了主题帖:
【STM32 H533RE】测评九_spi加oled的简单测试
本帖最后由 Zhao_kar 于 2025-3-23 21:20 编辑
【STM32 H533RE】测评九_spi加oled的简单测试
备注:最后一节,也就是计划中的spi部分,整体项目因为LS原因先不上传,预计6月底会把整个项目端上来,其他的后续再说吧,现阶段就先按照计划做到这里,spi部分跟IIC部分类似,同样都是调库驱动显示屏,大部分驱动市面上都已经成型了,不再多说(原理也不讲了,之前记得应该写过帖子,不太清楚了),步骤如下:
一、cubemx部分
1、RCC
2、时钟树
3、SPI配置
二、代码部分
先把oled的三个文件写好,扔到src和inc里面,直接在ide新建之后再复制粘贴也可以用
//oledc
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include <stdio.h> // snprintf 需要的头文件
#include <string.h> // strlen 需要的头文件
u8 OLED_GRAM[128][8];//
void OLED_Refresh_Gram(void)
//刷新oled的显示缓冲区,放在while里面
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++) OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);
}
}
//向OLED写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
//这个函数用于向OLED写入一个字节的数据或命令。
//参数 dat 表示要写入的数据,cmd 表示数据或命令标志(0表示命令,1表示数据)。
//该函数通过位操作将数据发送到OLED显示屏。
{
u8 i;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
for(i=0;i<8;i++)
{
OLED_SCL_Clr();
if(dat&0x80)
OLED_SDA_Set();
else
OLED_SDA_Clr();
OLED_SCL_Set();
dat<<=1;
}
OLED_DC_Set();
}
//开启OLED显示
void OLED_Display_On(void)
//这个函数用于开启OLED显示。它发送一系列命令来启动OLED显示屏的各种功能。
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
//这个函数用于关闭OLED显示。它发送一系列命令来关闭OLED显示屏的各种功能。
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)for(n=0;n<128;n++)
OLED_GRAM[n][i] = 0X00;
OLED_Refresh_Gram();//更新显示
}
//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
void OLED_DrawPoint(u8 x,u8 y,u8 t)
//这个函数用于在指定坐标位置画点。x 和 y 表示要绘制的点的坐标,t 为1表示填充点,0表示清空点。
{
u8 pos,bx,temp=0;
if(x>127||y>63)return;//超出范围了.
pos=7-y/8;
bx=y%8;
temp=1<<(7-bx);
if(t)OLED_GRAM[x][pos]|=temp;
else OLED_GRAM[x][pos]&=~temp;
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
//这个函数用于在指定位置显示一个字符。x 和 y 表示字符的起始坐标,chr 表示要显示的字符,size 表示字符的大小,mode 为0表示反白显示,1表示正常显示。
{
u8 temp,t,t1;
u8 y0=y;
chr=chr-' ';//得到偏移后的值
for(t=0;t<size;t++)
{
if(size==12)temp=oled_asc2_1206[chr][t]; //调用1206字体
else temp=oled_asc2_1608[chr][t]; //调用1608字体
for(t1=0;t1<8;t1++)
{
if(temp&0x80)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp<<=1;
y++;
if((y-y0)==size)
{
y=y0;
x++;
break;
}
}
}
}
//m^n函数,这个函数用于计算 m 的 n 次方。
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNumber(u8 x,u8 y,u32 num,u8 len,u8 size)
//这个函数用于在指定位置显示一个数字。x 和 y 表示数字的起始坐标,num 表示要显示的数字,len 表示数字的位数,size 表示数字的大小。
{
u8 t,temp;
u8 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+(size/2)*t,y,' ',size,1);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1);
}
}
//显示字符串
//x,y:起点坐标
//*p:字符串起始地址
//用16字体
void OLED_ShowString(u8 x,u8 y,const u8 *p)
//这个函数用于在指定位置显示一个字符串。x 和 y 表示字符串的起始坐标,p 是指向要显示的字符串的指针。
{
#define MAX_CHAR_POSX 122
#define MAX_CHAR_POSY 58
while(*p!='\0')
{
if(x>MAX_CHAR_POSX){x=0;y+=16;}
if(y > MAX_CHAR_POSY) {
x = 0;
y = 0;
OLED_Clear();
}
OLED_ShowChar(x,y,*p,12,1);
x+=8;
p++;
}
}
//显示浮点数字
//x,y :起点坐标
//value :要显示的值
//decimalPlaces,小数点后位数,
// 显示浮点数函数
//这个函数用于在指定位置显示一个浮点数。value 表示要显示的浮点数,decimalPlaces 表示小数点后的位数,x 和 y 表示浮点数的起始坐
void OLED_ShowFloat(float value, uint8_t decimalPlaces, uint8_t x, uint8_t y)
{
char buffer[16];
// 将浮点数转换为字符串格式,并指定小数位数
snprintf(buffer, sizeof(buffer), "%.*f", decimalPlaces, value);
// 在指定位置显示字符串
for (uint8_t i = 0; i < strlen(buffer); i++)
{
OLED_ShowChar(x + i * 8, y, buffer[i], 16, 1);
}
}
//初始化OLED
//这个函数用于初始化OLED显示屏。它发送一系列命令来配置OLED的参数,包括显示模式、对比度、偏移等。
void OLED_Init(void)
{
OLED_RES_Clr();
HAL_Delay(100);
OLED_RES_Set();
OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率
OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64)
OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
OLED_WR_Byte(0X00,OLED_CMD); //默认为0
OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示
OLED_WR_Byte(0xAF,OLED_CMD); //开启显示
OLED_Clear();
}
oledh
#ifndef OLED_H_
#define OLED_H_
#include "main.h"
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
//-----------------OLED端口定义----------------
//pa5-dc pa6-res pa7-sda pc6-scl
#define OLED_RES_Clr() HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_RESET) //RST
#define OLED_RES_Set() HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_SET) //RST
#define OLED_DC_Clr() HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET) //DC
#define OLED_DC_Set() HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_SET) //DC
#define OLED_SCL_Clr() HAL_GPIO_WritePin(OLED_SCL_GPIO_Port, OLED_SCL_Pin, GPIO_PIN_RESET) //SCL
#define OLED_SCL_Set() HAL_GPIO_WritePin(OLED_SCL_GPIO_Port, OLED_SCL_Pin, GPIO_PIN_SET) //SCL
#define OLED_SDA_Clr() HAL_GPIO_WritePin(OLED_SDA_GPIO_Port, OLED_SDA_Pin, GPIO_PIN_RESET) //SDA
#define OLED_SDA_Set() HAL_GPIO_WritePin(OLED_SDA_GPIO_Port, OLED_SDA_Pin, GPIO_PIN_SET) //SDA
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Refresh_Gram(void);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
void OLED_ShowNumber(u8 x,u8 y,u32 num,u8 len,u8 size);
void OLED_ShowString(u8 x,u8 y,const u8 *p);
void OLED_ShowFloatNum(u8 x,u8 y,float num,u8 size1);
void OLED_ShowFloat(float value, uint8_t decimalPlaces, uint8_t x, uint8_t y);
void OLED_ShowFNum(u8 x,u8 y,float num,u8 len,u8 size,u8 mode);
#endif /* OLED_H_ */
oledfonth
#ifndef OLEDFONT_H_
#define OLEDFONT_H_
//常用ASCII表
//偏移量32
//ASCII字符集
//偏移量32
//大小:12*6
const unsigned char oled_asc2_1206[95][12]={
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
{0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
{0x00,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x00,0x00},/*""",2*/
{0x09,0x00,0x0B,0xC0,0x3D,0x00,0x0B,0xC0,0x3D,0x00,0x09,0x00},/*"#",3*/
{0x18,0xC0,0x24,0x40,0x7F,0xE0,0x22,0x40,0x31,0x80,0x00,0x00},/*"$",4*/
{0x18,0x00,0x24,0xC0,0x1B,0x00,0x0D,0x80,0x32,0x40,0x01,0x80},/*"%",5*/
{0x03,0x80,0x1C,0x40,0x27,0x40,0x1C,0x80,0x07,0x40,0x00,0x40},/*"&",6*/
{0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x20,0x40,0x40,0x20},/*"(",8*/
{0x00,0x00,0x40,0x20,0x20,0x40,0x1F,0x80,0x00,0x00,0x00,0x00},/*")",9*/
{0x09,0x00,0x06,0x00,0x1F,0x80,0x06,0x00,0x09,0x00,0x00,0x00},/*"*",10*/
{0x04,0x00,0x04,0x00,0x3F,0x80,0x04,0x00,0x04,0x00,0x00,0x00},/*"+",11*/
{0x00,0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/
{0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00},/*"-",13*/
{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/
{0x00,0x20,0x01,0xC0,0x06,0x00,0x38,0x00,0x40,0x00,0x00,0x00},/*"/",15*/
{0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"0",16*/
{0x00,0x00,0x10,0x40,0x3F,0xC0,0x00,0x40,0x00,0x00,0x00,0x00},/*"1",17*/
{0x18,0xC0,0x21,0x40,0x22,0x40,0x24,0x40,0x18,0x40,0x00,0x00},/*"2",18*/
{0x10,0x80,0x20,0x40,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"3",19*/
{0x02,0x00,0x0D,0x00,0x11,0x00,0x3F,0xC0,0x01,0x40,0x00,0x00},/*"4",20*/
{0x3C,0x80,0x24,0x40,0x24,0x40,0x24,0x40,0x23,0x80,0x00,0x00},/*"5",21*/
{0x1F,0x80,0x24,0x40,0x24,0x40,0x34,0x40,0x03,0x80,0x00,0x00},/*"6",22*/
{0x30,0x00,0x20,0x00,0x27,0xC0,0x38,0x00,0x20,0x00,0x00,0x00},/*"7",23*/
{0x1B,0x80,0x24,0x40,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"8",24*/
{0x1C,0x00,0x22,0xC0,0x22,0x40,0x22,0x40,0x1F,0x80,0x00,0x00},/*"9",25*/
{0x00,0x00,0x00,0x00,0x08,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/
{0x00,0x00,0x00,0x00,0x04,0x60,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/
{0x00,0x00,0x04,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0x40,0x40},/*"<",28*/
{0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x00,0x00},/*"=",29*/
{0x00,0x00,0x40,0x40,0x20,0x80,0x11,0x00,0x0A,0x00,0x04,0x00},/*">",30*/
{0x18,0x00,0x20,0x00,0x23,0x40,0x24,0x00,0x18,0x00,0x00,0x00},/*"?",31*/
{0x1F,0x80,0x20,0x40,0x27,0x40,0x29,0x40,0x1F,0x40,0x00,0x00},/*"@",32*/
{0x00,0x40,0x07,0xC0,0x39,0x00,0x0F,0x00,0x01,0xC0,0x00,0x40},/*"A",33*/
{0x20,0x40,0x3F,0xC0,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"B",34*/
{0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x30,0x80,0x00,0x00},/*"C",35*/
{0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"D",36*/
{0x20,0x40,0x3F,0xC0,0x24,0x40,0x2E,0x40,0x30,0xC0,0x00,0x00},/*"E",37*/
{0x20,0x40,0x3F,0xC0,0x24,0x40,0x2E,0x00,0x30,0x00,0x00,0x00},/*"F",38*/
{0x0F,0x00,0x10,0x80,0x20,0x40,0x22,0x40,0x33,0x80,0x02,0x00},/*"G",39*/
{0x20,0x40,0x3F,0xC0,0x04,0x00,0x04,0x00,0x3F,0xC0,0x20,0x40},/*"H",40*/
{0x20,0x40,0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x00,0x00},/*"I",41*/
{0x00,0x60,0x20,0x20,0x20,0x20,0x3F,0xC0,0x20,0x00,0x20,0x00},/*"J",42*/
{0x20,0x40,0x3F,0xC0,0x24,0x40,0x0B,0x00,0x30,0xC0,0x20,0x40},/*"K",43*/
{0x20,0x40,0x3F,0xC0,0x20,0x40,0x00,0x40,0x00,0x40,0x00,0xC0},/*"L",44*/
{0x3F,0xC0,0x3C,0x00,0x03,0xC0,0x3C,0x00,0x3F,0xC0,0x00,0x00},/*"M",45*/
{0x20,0x40,0x3F,0xC0,0x0C,0x40,0x23,0x00,0x3F,0xC0,0x20,0x00},/*"N",46*/
{0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"O",47*/
{0x20,0x40,0x3F,0xC0,0x24,0x40,0x24,0x00,0x18,0x00,0x00,0x00},/*"P",48*/
{0x1F,0x80,0x21,0x40,0x21,0x40,0x20,0xE0,0x1F,0xA0,0x00,0x00},/*"Q",49*/
{0x20,0x40,0x3F,0xC0,0x24,0x40,0x26,0x00,0x19,0xC0,0x00,0x40},/*"R",50*/
{0x18,0xC0,0x24,0x40,0x24,0x40,0x22,0x40,0x31,0x80,0x00,0x00},/*"S",51*/
{0x30,0x00,0x20,0x40,0x3F,0xC0,0x20,0x40,0x30,0x00,0x00,0x00},/*"T",52*/
{0x20,0x00,0x3F,0x80,0x00,0x40,0x00,0x40,0x3F,0x80,0x20,0x00},/*"U",53*/
{0x20,0x00,0x3E,0x00,0x01,0xC0,0x07,0x00,0x38,0x00,0x20,0x00},/*"V",54*/
{0x38,0x00,0x07,0xC0,0x3C,0x00,0x07,0xC0,0x38,0x00,0x00,0x00},/*"W",55*/
{0x20,0x40,0x39,0xC0,0x06,0x00,0x39,0xC0,0x20,0x40,0x00,0x00},/*"X",56*/
{0x20,0x00,0x38,0x40,0x07,0xC0,0x38,0x40,0x20,0x00,0x00,0x00},/*"Y",57*/
{0x30,0x40,0x21,0xC0,0x26,0x40,0x38,0x40,0x20,0xC0,0x00,0x00},/*"Z",58*/
{0x00,0x00,0x00,0x00,0x7F,0xE0,0x40,0x20,0x40,0x20,0x00,0x00},/*"[",59*/
{0x00,0x00,0x70,0x00,0x0C,0x00,0x03,0x80,0x00,0x40,0x00,0x00},/*"\",60*/
{0x00,0x00,0x40,0x20,0x40,0x20,0x7F,0xE0,0x00,0x00,0x00,0x00},/*"]",61*/
{0x00,0x00,0x20,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00},/*"^",62*/
{0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10},/*"_",63*/
{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/
{0x00,0x00,0x02,0x80,0x05,0x40,0x05,0x40,0x03,0xC0,0x00,0x40},/*"a",65*/
{0x20,0x00,0x3F,0xC0,0x04,0x40,0x04,0x40,0x03,0x80,0x00,0x00},/*"b",66*/
{0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x40,0x06,0x40,0x00,0x00},/*"c",67*/
{0x00,0x00,0x03,0x80,0x04,0x40,0x24,0x40,0x3F,0xC0,0x00,0x40},/*"d",68*/
{0x00,0x00,0x03,0x80,0x05,0x40,0x05,0x40,0x03,0x40,0x00,0x00},/*"e",69*/
{0x00,0x00,0x04,0x40,0x1F,0xC0,0x24,0x40,0x24,0x40,0x20,0x00},/*"f",70*/
{0x00,0x00,0x02,0xE0,0x05,0x50,0x05,0x50,0x06,0x50,0x04,0x20},/*"g",71*/
{0x20,0x40,0x3F,0xC0,0x04,0x40,0x04,0x00,0x03,0xC0,0x00,0x40},/*"h",72*/
{0x00,0x00,0x04,0x40,0x27,0xC0,0x00,0x40,0x00,0x00,0x00,0x00},/*"i",73*/
{0x00,0x10,0x00,0x10,0x04,0x10,0x27,0xE0,0x00,0x00,0x00,0x00},/*"j",74*/
{0x20,0x40,0x3F,0xC0,0x01,0x40,0x07,0x00,0x04,0xC0,0x04,0x40},/*"k",75*/
{0x20,0x40,0x20,0x40,0x3F,0xC0,0x00,0x40,0x00,0x40,0x00,0x00},/*"l",76*/
{0x07,0xC0,0x04,0x00,0x07,0xC0,0x04,0x00,0x03,0xC0,0x00,0x00},/*"m",77*/
{0x04,0x40,0x07,0xC0,0x04,0x40,0x04,0x00,0x03,0xC0,0x00,0x40},/*"n",78*/
{0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x40,0x03,0x80,0x00,0x00},/*"o",79*/
{0x04,0x10,0x07,0xF0,0x04,0x50,0x04,0x40,0x03,0x80,0x00,0x00},/*"p",80*/
{0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x50,0x07,0xF0,0x00,0x10},/*"q",81*/
{0x04,0x40,0x07,0xC0,0x02,0x40,0x04,0x00,0x04,0x00,0x00,0x00},/*"r",82*/
{0x00,0x00,0x06,0x40,0x05,0x40,0x05,0x40,0x04,0xC0,0x00,0x00},/*"s",83*/
{0x00,0x00,0x04,0x00,0x1F,0x80,0x04,0x40,0x00,0x40,0x00,0x00},/*"t",84*/
{0x04,0x00,0x07,0x80,0x00,0x40,0x04,0x40,0x07,0xC0,0x00,0x40},/*"u",85*/
{0x04,0x00,0x07,0x00,0x04,0xC0,0x01,0x80,0x06,0x00,0x04,0x00},/*"v",86*/
{0x06,0x00,0x01,0xC0,0x07,0x00,0x01,0xC0,0x06,0x00,0x00,0x00},/*"w",87*/
{0x04,0x40,0x06,0xC0,0x01,0x00,0x06,0xC0,0x04,0x40,0x00,0x00},/*"x",88*/
{0x04,0x10,0x07,0x10,0x04,0xE0,0x01,0x80,0x06,0x00,0x04,0x00},/*"y",89*/
{0x00,0x00,0x04,0x40,0x05,0xC0,0x06,0x40,0x04,0x40,0x00,0x00},/*"z",90*/
{0x00,0x00,0x00,0x00,0x04,0x00,0x7B,0xE0,0x40,0x20,0x00,0x00},/*"{",91*/
{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00},/*"|",92*/
{0x00,0x00,0x40,0x20,0x7B,0xE0,0x04,0x00,0x00,0x00,0x00,0x00},/*"}",93*/
{0x40,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x40,0x00},/*"~",94*/
};
const unsigned char oled_asc2_1608[95][16]={
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xCC,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
{0x00,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x00,0x00},/*""",2*/
{0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x00,0x00},/*"#",3*/
{0x00,0x00,0x0E,0x18,0x11,0x04,0x3F,0xFF,0x10,0x84,0x0C,0x78,0x00,0x00,0x00,0x00},/*"$",4*/
{0x0F,0x00,0x10,0x84,0x0F,0x38,0x00,0xC0,0x07,0x78,0x18,0x84,0x00,0x78,0x00,0x00},/*"%",5*/
{0x00,0x78,0x0F,0x84,0x10,0xC4,0x11,0x24,0x0E,0x98,0x00,0xE4,0x00,0x84,0x00,0x08},/*"&",6*/
{0x08,0x00,0x68,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x18,0x18,0x20,0x04,0x40,0x02,0x00,0x00},/*"(",8*/
{0x00,0x00,0x40,0x02,0x20,0x04,0x18,0x18,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/
{0x02,0x40,0x02,0x40,0x01,0x80,0x0F,0xF0,0x01,0x80,0x02,0x40,0x02,0x40,0x00,0x00},/*"*",10*/
{0x00,0x80,0x00,0x80,0x00,0x80,0x0F,0xF8,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00},/*"+",11*/
{0x00,0x01,0x00,0x0D,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/
{0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80},/*"-",13*/
{0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/
{0x00,0x00,0x00,0x06,0x00,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x18,0x00,0x20,0x00},/*"/",15*/
{0x00,0x00,0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"0",16*/
{0x00,0x00,0x08,0x04,0x08,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"1",17*/
{0x00,0x00,0x0E,0x0C,0x10,0x14,0x10,0x24,0x10,0x44,0x11,0x84,0x0E,0x0C,0x00,0x00},/*"2",18*/
{0x00,0x00,0x0C,0x18,0x10,0x04,0x11,0x04,0x11,0x04,0x12,0x88,0x0C,0x70,0x00,0x00},/*"3",19*/
{0x00,0x00,0x00,0xE0,0x03,0x20,0x04,0x24,0x08,0x24,0x1F,0xFC,0x00,0x24,0x00,0x00},/*"4",20*/
{0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",21*/
{0x00,0x00,0x07,0xF0,0x08,0x88,0x11,0x04,0x11,0x04,0x18,0x88,0x00,0x70,0x00,0x00},/*"6",22*/
{0x00,0x00,0x1C,0x00,0x10,0x00,0x10,0xFC,0x13,0x00,0x1C,0x00,0x10,0x00,0x00,0x00},/*"7",23*/
{0x00,0x00,0x0E,0x38,0x11,0x44,0x10,0x84,0x10,0x84,0x11,0x44,0x0E,0x38,0x00,0x00},/*"8",24*/
{0x00,0x00,0x07,0x00,0x08,0x8C,0x10,0x44,0x10,0x44,0x08,0x88,0x07,0xF0,0x00,0x00},/*"9",25*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x03,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/
{0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/
{0x00,0x00,0x00,0x80,0x01,0x40,0x02,0x20,0x04,0x10,0x08,0x08,0x10,0x04,0x00,0x00},/*"<",28*/
{0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x00,0x00},/*"=",29*/
{0x00,0x00,0x10,0x04,0x08,0x08,0x04,0x10,0x02,0x20,0x01,0x40,0x00,0x80,0x00,0x00},/*">",30*/
{0x00,0x00,0x0E,0x00,0x12,0x00,0x10,0x0C,0x10,0x6C,0x10,0x80,0x0F,0x00,0x00,0x00},/*"?",31*/
{0x03,0xE0,0x0C,0x18,0x13,0xE4,0x14,0x24,0x17,0xC4,0x08,0x28,0x07,0xD0,0x00,0x00},/*"@",32*/
{0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04},/*"A",33*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x11,0x04,0x0E,0x88,0x00,0x70,0x00,0x00},/*"B",34*/
{0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x1C,0x10,0x00,0x00},/*"C",35*/
{0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"D",36*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x17,0xC4,0x10,0x04,0x08,0x18,0x00,0x00},/*"E",37*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x17,0xC0,0x10,0x00,0x08,0x00,0x00,0x00},/*"F",38*/
{0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x44,0x1C,0x78,0x00,0x40,0x00,0x00},/*"G",39*/
{0x10,0x04,0x1F,0xFC,0x10,0x84,0x00,0x80,0x00,0x80,0x10,0x84,0x1F,0xFC,0x10,0x04},/*"H",40*/
{0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x00,0x00,0x00,0x00},/*"I",41*/
{0x00,0x03,0x00,0x01,0x10,0x01,0x10,0x01,0x1F,0xFE,0x10,0x00,0x10,0x00,0x00,0x00},/*"J",42*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x03,0x80,0x14,0x64,0x18,0x1C,0x10,0x04,0x00,0x00},/*"K",43*/
{0x10,0x04,0x1F,0xFC,0x10,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x0C,0x00,0x00},/*"L",44*/
{0x10,0x04,0x1F,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x1F,0xFC,0x10,0x04,0x00,0x00},/*"M",45*/
{0x10,0x04,0x1F,0xFC,0x0C,0x04,0x03,0x00,0x00,0xE0,0x10,0x18,0x1F,0xFC,0x10,0x00},/*"N",46*/
{0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"O",47*/
{0x10,0x04,0x1F,0xFC,0x10,0x84,0x10,0x80,0x10,0x80,0x10,0x80,0x0F,0x00,0x00,0x00},/*"P",48*/
{0x07,0xF0,0x08,0x18,0x10,0x24,0x10,0x24,0x10,0x1C,0x08,0x0A,0x07,0xF2,0x00,0x00},/*"Q",49*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x11,0xC0,0x11,0x30,0x0E,0x0C,0x00,0x04},/*"R",50*/
{0x00,0x00,0x0E,0x1C,0x11,0x04,0x10,0x84,0x10,0x84,0x10,0x44,0x1C,0x38,0x00,0x00},/*"S",51*/
{0x18,0x00,0x10,0x00,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x00,0x18,0x00,0x00,0x00},/*"T",52*/
{0x10,0x00,0x1F,0xF8,0x10,0x04,0x00,0x04,0x00,0x04,0x10,0x04,0x1F,0xF8,0x10,0x00},/*"U",53*/
{0x10,0x00,0x1E,0x00,0x11,0xE0,0x00,0x1C,0x00,0x70,0x13,0x80,0x1C,0x00,0x10,0x00},/*"V",54*/
{0x1F,0xC0,0x10,0x3C,0x00,0xE0,0x1F,0x00,0x00,0xE0,0x10,0x3C,0x1F,0xC0,0x00,0x00},/*"W",55*/
{0x10,0x04,0x18,0x0C,0x16,0x34,0x01,0xC0,0x01,0xC0,0x16,0x34,0x18,0x0C,0x10,0x04},/*"X",56*/
{0x10,0x00,0x1C,0x00,0x13,0x04,0x00,0xFC,0x13,0x04,0x1C,0x00,0x10,0x00,0x00,0x00},/*"Y",57*/
{0x08,0x04,0x10,0x1C,0x10,0x64,0x10,0x84,0x13,0x04,0x1C,0x04,0x10,0x18,0x00,0x00},/*"Z",58*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x40,0x02,0x40,0x02,0x40,0x02,0x00,0x00},/*"[",59*/
{0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x80,0x00,0x60,0x00,0x1C,0x00,0x03,0x00,0x00},/*"\",60*/
{0x00,0x00,0x40,0x02,0x40,0x02,0x40,0x02,0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/
{0x00,0x00,0x00,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00},/*"^",62*/
{0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01},/*"_",63*/
{0x00,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/
{0x00,0x00,0x00,0x98,0x01,0x24,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xFC,0x00,0x04},/*"a",65*/
{0x10,0x00,0x1F,0xFC,0x00,0x88,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"b",66*/
{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x00},/*"c",67*/
{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x11,0x08,0x1F,0xFC,0x00,0x04},/*"d",68*/
{0x00,0x00,0x00,0xF8,0x01,0x44,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xC8,0x00,0x00},/*"e",69*/
{0x00,0x00,0x01,0x04,0x01,0x04,0x0F,0xFC,0x11,0x04,0x11,0x04,0x11,0x00,0x18,0x00},/*"f",70*/
{0x00,0x00,0x00,0xD6,0x01,0x29,0x01,0x29,0x01,0x29,0x01,0xC9,0x01,0x06,0x00,0x00},/*"g",71*/
{0x10,0x04,0x1F,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"h",72*/
{0x00,0x00,0x01,0x04,0x19,0x04,0x19,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"i",73*/
{0x00,0x00,0x00,0x03,0x00,0x01,0x01,0x01,0x19,0x01,0x19,0xFE,0x00,0x00,0x00,0x00},/*"j",74*/
{0x10,0x04,0x1F,0xFC,0x00,0x24,0x00,0x40,0x01,0xB4,0x01,0x0C,0x01,0x04,0x00,0x00},/*"k",75*/
{0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"l",76*/
{0x01,0x04,0x01,0xFC,0x01,0x04,0x01,0x00,0x01,0xFC,0x01,0x04,0x01,0x00,0x00,0xFC},/*"m",77*/
{0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"n",78*/
{0x00,0x00,0x00,0xF8,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0xF8,0x00,0x00},/*"o",79*/
{0x01,0x01,0x01,0xFF,0x00,0x85,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"p",80*/
{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0xFF,0x00,0x01},/*"q",81*/
{0x01,0x04,0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x04,0x01,0x00,0x01,0x80,0x00,0x00},/*"r",82*/
{0x00,0x00,0x00,0xCC,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x98,0x00,0x00},/*"s",83*/
{0x00,0x00,0x01,0x00,0x01,0x00,0x07,0xF8,0x01,0x04,0x01,0x04,0x00,0x00,0x00,0x00},/*"t",84*/
{0x01,0x00,0x01,0xF8,0x00,0x04,0x00,0x04,0x00,0x04,0x01,0x08,0x01,0xFC,0x00,0x04},/*"u",85*/
{0x01,0x00,0x01,0x80,0x01,0x70,0x00,0x0C,0x00,0x10,0x01,0x60,0x01,0x80,0x01,0x00},/*"v",86*/
{0x01,0xF0,0x01,0x0C,0x00,0x30,0x01,0xC0,0x00,0x30,0x01,0x0C,0x01,0xF0,0x01,0x00},/*"w",87*/
{0x00,0x00,0x01,0x04,0x01,0x8C,0x00,0x74,0x01,0x70,0x01,0x8C,0x01,0x04,0x00,0x00},/*"x",88*/
{0x01,0x01,0x01,0x81,0x01,0x71,0x00,0x0E,0x00,0x18,0x01,0x60,0x01,0x80,0x01,0x00},/*"y",89*/
{0x00,0x00,0x01,0x84,0x01,0x0C,0x01,0x34,0x01,0x44,0x01,0x84,0x01,0x0C,0x00,0x00},/*"z",90*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x3E,0xFC,0x40,0x02,0x40,0x02},/*"{",91*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/
{0x00,0x00,0x40,0x02,0x40,0x02,0x3E,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/
{0x00,0x00,0x60,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00},/*"~",94*/
};
#endif /* OLEDFONT_H_ */
引脚部分自己注意点,这部分就不说明了。
然后是主函数部分,简单写个测试就行
/* USER CODE BEGIN 2 */
// 初始化 OLED
OLED_Init();
// 清屏
OLED_Clear();
// 显示静态文本
OLED_ShowString(10, 10, (uint8_t *)"SPI OLED Test");
// 显示动态数值
float temp = 24.6;
float humi = 45.2;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 清除之前的数值显示(避免重叠)
OLED_ShowString(10, 30, (uint8_t *)"Temp: ");
OLED_ShowString(10, 50, (uint8_t *)"Humi: ");
// 显示新的数值
OLED_ShowFloat(temp, 1, 60, 30);
OLED_ShowFloat(humi, 1, 60, 50);
// 模拟温湿度变化
temp += 0.1;
if (temp > 30.0) temp = 24.6;
humi += 0.2;
if (humi > 50.0) humi = 45.2;
// 刷新显示
OLED_Refresh_Gram();
// 延迟 500ms
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
最后测试结果如图
-
发表了主题帖:
【STM32 H533RE】测评七_常见温度传感器ds18b20测试
本帖最后由 Zhao_kar 于 2025-3-23 16:50 编辑
【STM32 H533RE】测评七_常见温度传感器ds18b20测试
备注:本节主要讲一下简单驱动ds18b20,就不写传感器的详解了,因为这个传感器网上哪里都有资料,而且视频教程也很多,就做个简单的测试,下一节补aht10的驱动,然后原定的ld
3320没用上,为了替代spi的测试,会补一篇oled的,整体的实现因为个人原因就先不做演示了,预计等到6月底之后有时间再补上。
一、ds18b20的原理和配置思路
首先是基本原理,ds18b20模块采用的是1-wire通信协议,也就是常说的单总线,一般的通信流程如下:
1、先是复位脉冲,主机拉低总线,480us之后再释放,总线由外部上拉电阻拉高,一般模块自带这个电阻,详情看买的店家
2、从机检测到复位信号之后,要在延迟之后通知主机存在
3、然后主机发送命令,比如跳过rom,代码里的0xcc;匹配0x55等等
4、最后做数据读取,以lsb方式返回温度数据,数据表格是16位的补码形式
但是说了这些东西其实也不需要太了解,如果想自己深入学习,去把英文文档扒着看看就知道了,如果只是要直接用在项目上,直接照着网上的库写就行了,毕竟是一个比较简单的传感器。
然后硬件部分,只需要一个dq数据线,然后供电vcc和接地gnd就行(要不然为啥叫单总线)
然后是代码开发部分,简单说一下思路:
因为ds18b20是单总线,他肯定是要发送数据的同时也要符合接受数据,所以gpio要设置成推挽输出,gpio的常见设置这里不提及。
然后到复位和存在脉冲的检测,所以先拉低总线,这里拉低之后要延迟750us,然后再释放,再检测相应信号
数据读写部分就是写几个函数,读取一个bit的,读取一个字节的,写入一个字节的,读取的时候是主机发起始信号,然后再读,写入的时候是主机先拉低总线,然后根据数据位设定时序。
最后是读取温度,这个会写一个函数,然后直接扔到主函数里面去用,温度数据会存储在两个字节中,以补码的形式表示,第四位是小数位,所以设定变量会分开,进而存储整数的数据和小数的数据。然后具体过程大概就是先用wirtebyte函数,启动温度转换,然后有一个750ms的延时,这个是等待转换,转换完成之后再读温度数据,读完之后把数据放在两个变量里面,做一些数据处理操作就行,也就是补码的转换,差不多就是这么个思路,说到这里,我觉得理论的东西太多了,真想深入学还是乖乖去看英文文档吧,接下来就是cubemx部分的配置和最后ide里面的代码编写。
二、cubemx的基础操作
没啥好配置的,就一个IO口,然后方便调试开个串口,设个时钟树
三、代码编写
这边把c文件和h文件放到最后再补充,直接把c和h文件扔到src和inc文件夹里面就行,自己建个文件夹然后加个路径也可以
然后串口部分老样子,如下:
/* USER CODE BEGIN 1 */
#include <stdio.h>
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
/* USER CODE END 1 */
由于ds18b20要us的延时,hal没有,所以我们在tim里面写一个us延时函数,如下:
/* USER CODE BEGIN 1 */
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] 微秒级延时函数
* @param us 需要延迟的时间(单位:微秒)
* @note 该函数使用定时器 TIM1 进行微秒级精确延时
*/
void delay_us(uint16_t us)
{
uint16_t differ = 0xFFFF - us - 5; // 计算定时器计数器起始值,减去5进行补偿
__HAL_TIM_SET_COUNTER(&htim1, differ); // 设置定时器的计数器值
HAL_TIM_Base_Start(&htim1); // 启动定时器
// 等待计数器达到设定值,确保延时精度
while (differ < 0xFFFF - 6)
{
differ = __HAL_TIM_GET_COUNTER(&htim1); // 读取当前定时器计数值
}
HAL_TIM_Base_Stop(&htim1); // 停止定时器
}
/* USER CODE END 1 */
同时别忘了补声明:
/* USER CODE BEGIN Prototypes */
void delay_us(uint16_t us);
/* USER CODE END Prototypes */
us延时写完之后,就可以开始写ds18b20函数了,如下:
#include "ds18b20.h"
#include "tim.h"
/**
* @brief 设置 DS18B20 引脚为推挽输出模式
*/
static void DS18B20_Mode_OUT_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DS18B20_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
}
/**
* @brief 设置 DS18B20 引脚为输入模式(无上拉)
*/
static void DS18B20_Mode_IN_NP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DS18B20_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
}
/**
* @brief 发送复位脉冲,初始化 DS18B20
* @note 主机拉低总线至少 480us 以触发 DS18B20 复位
*/
static void DS18B20_Reset(void)
{
DS18B20_Mode_OUT_PP(); // 设置为输出模式
DS18B20_OUT_0; // 拉低总线,发送复位信号
delay_us(750);
DS18B20_OUT_1; // 释放总线,等待 DS18B20 响应
delay_us(15); // 等待从机响应
}
/**
* @brief 检测 DS18B20 是否存在
* [url=home.php?mod=space&uid=784970]@return[/url] 0:存在,1:不存在
*/
static uint8_t DS18B20_Presence(void)
{
uint8_t pulse_time = 0;
DS18B20_Mode_IN_NP(); // 设置为输入模式
// 等待 DS18B20 发送存在脉冲(60~240us 的低电平)
while (DS18B20_IN && (pulse_time < 100)) // 等待低电平
{
pulse_time++;
delay_us(1);
}
if (pulse_time >= 100) // 超时未检测到低电平
{
return 1;
}
else
{
pulse_time = 0;
}
// 继续等待存在脉冲的结束
while (!(DS18B20_IN) && pulse_time < 240)
{
pulse_time++;
delay_us(1);
}
if (pulse_time >= 240)
{
return 1;
}
return 0;
}
/**
* @brief 初始化 DS18B20
* @return 0:成功,1:失败
*/
uint8_t DS18B20_Init(void)
{
DS18B20_Mode_OUT_PP();
DS18B20_OUT_1;
DS18B20_Reset();
return DS18B20_Presence();
}
/**
* @brief 读取 DS18B20 的 1bit 数据
* @return 读取到的 1bit 数据(0 或 1)
*/
static uint8_t DS18B20_ReadBit(void)
{
uint8_t dat;
DS18B20_Mode_OUT_PP(); // 设置为输出模式
DS18B20_OUT_0; // 发送读命令信号(拉低总线)
delay_us(10); // 确保信号稳定
DS18B20_Mode_IN_NP(); // 释放总线,读取数据
dat = DS18B20_IN; // 读取数据位
delay_us(45); // 等待数据稳定
return dat;
}
/**
* @brief 读取 DS18B20 的 1 字节数据(低位在前)
* @return 读取到的 8bit 数据
*/
static uint8_t DS18B20_ReadByte(void)
{
uint8_t i, dat = 0;
for(i = 0; i < 8; i++)
{
dat |= (DS18B20_ReadBit() << i);
}
return dat;
}
/**
* @brief 向 DS18B20 发送 1 字节数据(低位在前)
* @param dat: 要发送的 8bit 数据
*/
static void DS18B20_WriteByte(uint8_t dat)
{
uint8_t i;
DS18B20_Mode_OUT_PP();
for(i = 0; i < 8; i++)
{
if (dat & 0x01) // 发送 1
{
DS18B20_OUT_0;
delay_us(5);
DS18B20_OUT_1;
delay_us(65);
}
else // 发送 0
{
DS18B20_OUT_0;
delay_us(70);
DS18B20_OUT_1;
delay_us(2);
}
dat >>= 1;
}
}
/**
* @brief 跳过 ROM 直接对所有 DS18B20 发送命令
*/
static void DS18B20_SkipRom(void)
{
DS18B20_Reset();
DS18B20_Presence();
DS18B20_WriteByte(0XCC); /* 跳过 ROM */
}
/**
* @brief 获取 DS18B20 的温度值(跳过 ROM)
* @return 温度值(单位:摄氏度)
*/
float DS18B20_GetTemp_SkipRom(void)
{
uint8_t tpmsb, tplsb;
int16_t s_tem;
float f_tem;
DS18B20_SkipRom();
DS18B20_WriteByte(0X44); // 开始温度转换
HAL_Delay(750); // 等待转换完成
DS18B20_SkipRom();
DS18B20_WriteByte(0XBE); // 读取温度寄存器
tplsb = DS18B20_ReadByte();
tpmsb = DS18B20_ReadByte();
s_tem = (tpmsb << 8) | tplsb;
// 计算实际温度
if(s_tem < 0) // 负温度
{
f_tem = (~s_tem + 1) * 0.0625f;
}
else
{
f_tem = s_tem * 0.0625f;
}
return f_tem;
}
/**
* @brief 读取 DS18B20 的 ROM ID
* @param ds18b20_id: 用于存储 ID 的数组
*/
void DS18B20_ReadId(uint8_t *ds18b20_id)
{
uint8_t uc;
DS18B20_WriteByte(0x33); // 读取 ROM ID
for (uc = 0; uc < 8; uc++)
{
ds18b20_id[uc] = DS18B20_ReadByte();
}
}
然后h文件声明一下:
#ifndef __BSP_DS18B20_H
#define __BSP_DS18B20_H
#include "stm32h5xx_hal.h"
#include "main.h"
#define DS18B20_PORT DQ_GPIO_Port
#define DS18B20_PIN DQ_Pin
#define DS18B20_OUT_1 HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET)
#define DS18B20_OUT_0 HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET)
#define DS18B20_IN HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN)
uint8_t DS18B20_Init(void);
void DS18B20_ReadId(uint8_t *ds18b20_id);
float DS18B20_GetTemp_SkipRom(void);
float DS18B20_GetTemp_MatchRom(uint8_t * ds18b20_id);
#endif
基本准备就完成了,接下来写主函数
先是一些基础的定义和配置:
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "ds18b20.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
float temperature;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
//初始化
DS18B20_Init();
/* USER CODE END 2 */
然后直接调函数就行,把温度读取之后打印出来
/* USER CODE BEGIN 3 */
temperature = DS18B20_GetTemp_SkipRom();
printf("TEMP:%.2f\r\n", temperature);
HAL_Delay(1000);
}
/* USER CODE END 3 */
打印出来之后接个串口看看数据,今天南京气温如下:
测几次之后我会用手机握住传感器的探针,然后温度明显会上升,如下:
补一个实物图,硬件接线真没什么好说的,如下:
下一节是aht10的温湿度测试
- 2025-03-19
-
发表了主题帖:
【STM32 H533RE】测评六_官方自带温度传感器的尝试
本帖最后由 Zhao_kar 于 2025-3-19 19:56 编辑
【STM32 H533RE】测评六_官方自带温度传感器的尝试
备注:这一篇算是头一次尝试单片机自带的温度传感器,其实常用的h7也有,但是一直没用过,所以这一篇就简单按照当初计划说的试一试
一、内部温度传感器描述
首先在看h5的资料图的时候可以看到如下
明显可以看到,这个温度传感器是内置在adc里面的,应该是一个内部数字传感器,然后我们打开cubemx部分,在adc部分开一个通道,可以看到一个设置
再了解如何操作之前,先看一下官方文档内容,然后我们在这个文档去找资料
打开之后是一个h5的文档,在目录里面我们可以看到adc相关配置里面有内置温度传感器的资料
详细的步骤在文档里面都有,这里补一个通道数,明显是16通道
然后再看一下官方的算法 基本了解之后就可以开始配置了。
二、cubemx部分
这部分比较简单,首先是打开传感器部分,像前面一样,然后是周期按照需求改
然后串口老样子
时钟树核实一下
基本上cubemx就操作好了
三、写代码
我这边先给一个函数库,这部分有两种方法,第一种直接按照官方文档来写,第二种是去调用寄存器存的内容,我这边用的第一种,第二种用的人比较多,我这边只是简单测试,就不用了。
void Read_Internal_Temperature()
{
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) // 确保转换成功
{
uint32_t ADC_Value = HAL_ADC_GetValue(&hadc1);
printf("ADC1_IN16 ADC value: %d\r\n", ADC_Value);
float Vol_Value = ADC_Value * (VREF / ADC_RESOLUTION);
printf("ADC1_IN16 VOL value: %.2fV\r\n", Vol_Value);
float Temperature = (TS_CAL1_VOLTAGE - Vol_Value) / TS_SLOPE + TS_CAL1_TEMP;
printf("MCU Internal Temperature: %.2f°C\r\n", Temperature);
}
else
{
printf("ADC conversion timeout!\r\n");
}
HAL_Delay(1000);
}
把这部分函数写好,然后在主函数开头做一个宏定义
#define VREF 3.3
#define ADC_RESOLUTION 4096.0
#define TS_CAL1_TEMP 25.0
#define TS_CAL1_VOLTAGE 0.4
#define TS_SLOPE 0.01 // 传感器斜率
然后补充一点,配置这部分可以去adc里面看一下初始化的代码确认一下,也就是这部分
void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
做完这些之后就可以在while循环里面调用函数了,具体操作如下
/* USER CODE BEGIN 3 */
// HAL_ADC_Start(&hadc1);
// HAL_ADC_PollForConversion(&hadc1, 50);
//
// ADC_Value = HAL_ADC_GetValue(&hadc1); //读取ADC转换数据(16位数据)
// TS_CAL1 = *(__IO uint16_t *)(0x1FF1E820);
// TS_CAL2 = *(__IO uint16_t *)(0x1FF1E840);
// ADC_Value = ((110.0f - 30.0f) / (TS_CAL2 - TS_CAL1)) * (ADC_Value - TS_CAL1) + 30.0f;
// printf("%f\n",ADC_Value);
// HAL_Delay(1000);
Read_Internal_Temperature();
HAL_Delay(1000);
}
/* USER CODE END 3 */
然后我这部分是之前测试的按照地址读的方法,不同的芯片地址不一样,这边也不去试第二种方法了。
接下来就可以把代码烧录,然后看一下串口调试助手打印的数据(摄氏度那个句号稍微有点问题,不过无伤大雅)
然后我把板子稍微靠近灯带,温度也会上升
经过简单测试,内置温度器明显精读不够高,不够也就是测试玩玩,后面会上个专门的ds18b20和aht温湿度传感器测试
-
发表了主题帖:
【STM32 H533RE】测评五_DAC的基本原理和测试
本帖最后由 Zhao_kar 于 2025-3-19 15:23 编辑
【STM32 H533RE】测评五_DAC的基本原理和测试
备注:本节主要做dac的简单测试,具体操作为使用单片机自带的DAC生成一个信号,然后让adc重新采集,采集之后用串口打印,验证整个过程,实现之后可以看到串口打印的值即为设定的dac的值。
一、dac的原理
dac其实就是跟adc的ad反过来的,也就是把数字信号转换成模拟信号的设备,在h5的mcu里面,dac允许mcu直接输出可调的模拟电压信号,不需要外接dac模块,这个跟adc也是一样的,然后如果学过数电的,应该知道比较常见的就是权电阻网络和R2R的dac网络,还有倒t等等,本质上都是利用运放来设计的,详细就不说了,本篇就不像上一篇那么详细的说adc的原理了,两者其实是类似的思考方式,我们这边以两种方式来测试,一个是直接dac产生一个电压值,adc去测,第二种用cubemx自带的三角波波形,然后打印出来看看。
二、cubemx的配置
补充:在这一部分,配置dac时要设置一下通道,别用默认的pa4引脚,如果查阅过官方文档,就能明白我说的是什么意思了。
然后你去看板子原理图,应该是没有吧pa4拉出来,所以改换成pa5即可。
操作如下
时钟树同理上一篇
然后adc跟上一篇的操作是一样的,详见如下
操作完之后开一下串口,这边就老样子开的串口1
接下来就是dac的代码编写部分。
二、代码部分
/* USER CODE BEGIN 2 */
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
//HAL_TIM_Base_Start(&htim2);
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);//AD校准,单端输入
/* USER CODE END 2 */
这一部分是老样子,一个是adc的一个是adc的,此时我们dac会输出1.65v的电压,然后循环部分还是让adc采集电压,跟上一篇一样,如下
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);
HAL_ADC_Start(&hadc1); //启动ADC转换
HAL_ADC_PollForConversion(&hadc1, 50); //等待转换完成,50为最大等待时间,单位为ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
ADC_Value = HAL_ADC_GetValue(&hadc1); //获取AD值
printf("ADC1: %d \r\n",ADC_Value);
printf("V: %.4f \r\n",ADC_Value*3.3f/4096);
}
HAL_Delay(2000);
}
编译,烧录,然后在串口调试助手,就可以看到1,65v附近的电压了。
接下来测试完这个,我们再看三角波操作,先在cubemx里操作。
三、cubemx更改
我们要在dac这部分进行更改
然后这里面设置合适的值,我设的4095,然后打开定时器
生成代码之后只需要加一个定时器部分,然后其他部分没有什么太大变化,只需要把adc采集到的值打印出来即可
HAL_TIM_Base_Start(&htim2);
打印出来后见vofa的图
硬件连接实物如下
- 2025-03-18
-
发表了主题帖:
【STM32 H533RE】测评四_ADC和常见模拟输出模块的测试
本帖最后由 Zhao_kar 于 2025-3-18 21:34 编辑
【STM32 H533RE】测评四_ADC和常见模拟输出模块的测试
备注:本节讲一下ADC的基本原理,以及cubemx部分如何进行单片机自带adc的基本配置,然后会用一个光照度计的模块,这个模块可以做模拟输出也可以做数字输出,这边会用模拟输出,然后adc采集信号,最后读出照度值。然后基于此可以进阶,比如开dma,然后采集波形,打印串口去显示也是可以的。
一、ADC的基本原理
1、本文以单片机自带的12位3.3v的adc为例子进行说明
首先是精度的概念,12位adc,也就是2的12次方,所以是4096,然后我们单片机的电压采集范围是0-3.3v,所以把这个分成4096层,算出来结果就是0.0008v一档,这个就是分辨率的概念,也就是说这个adc只能区分这个范围内的参数,比如0v的时候adc返回0,那么0.0008返回就是1,但是你要想区分0.004那就行不通了。了解了基础概念之后,直接给出一个公式
这边举个例子比较通俗易懂,比如adc测一个1.65v的电压,那么adc会返回一个数字信号给mcu,也就是4096乘0.5等于2048,那么单片机会接受到这个数字,然后再通过单片机编程就可以得到电压值。
然后采样率的概念也比较简单,比如一个1s的sin波,对他进行采样的话,我们是按照点来采集的,比如你用0,1s的采样率,那么1s的sin波你就可以采集到十个点,以此类推,为了得到更多的点,比如1s波形,1hz,你想采集100个点,尽可能复现波形,那么就用100hz的adc采样率来进行采集就可以了。然后这里会涉及一个特殊情况,当你的单片机频率不足以采集到高频的信号的时候,比如你的单片机最快也就2Mhz的采样,一个50mhz的波形压根不能采集,这个时候就有其他方法了,比如使用专门的adc模块,然后用iic或者spi通信与单片机通信;也可以用特俗采样方法来进行采集,也可以换性能更好的单片机(比较少用),一般都是有专门的adc来干这个事情的
二、cubemx部分配置
基础配置和串口部分就不细说了,之前有讲过,配置完之后直接来adc部分
这里可以使用定时器来触发,不过我这边只是做个小测试,就拿默认软件触发,然后选择之后可以看到右边的pa0打开
然后是时钟部分的设置,h5的时钟树和f4和f1有点不太一样,不过无所谓,时钟配置根据需求来就行,我这边就随便设个50,都行。
然后勾选配置,generate
生成之后就可以写代码了,接下来到第三部分
三、代码编写和函数使用
在编写代码之前,我们需要了解一个大致流程,我们要做的操作首先是设置一个函数变量,用来存adc采集到的电压值,然后我们要做adc的初始化,这一部分hal会自带,然后我们要做adc的校准,校准之后流程基本不变,如启动adc转换,然后等待转换,之后我们再把转换后的函数赋值给变量,最后把变量的参数打印出来看。
然后这部分不是死的,比如用dma的时候,那么就是HAL_ADC_Start_DMA这个函数,我们这边不需要,直接HAL_ADC_Start(&hadc1);这个函数就可以,代码如下
/* USER CODE BEGIN 0 */
uint16_t ADC_Value;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);//AD校准,单端输入
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1); //启动ADC转换
HAL_ADC_PollForConversion(&hadc1, 50); //等待转换完成,50为最大等待时间,单位为ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
ADC_Value = HAL_ADC_GetValue(&hadc1); //获取AD值
printf("ADC1: %d \r\n",ADC_Value);
printf("V: %.4f \r\n",ADC_Value*3.3f/4096);
}
HAL_Delay(2000);
}
然后这里有一个地方要补充,关于下面这个校准函数,请自己去查看定义,每一代32芯片的库不是一样的
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);//AD校准,单端输入
比如你在f1里面,压根就不需要这么复杂,他只需要这样
HAL_ADCEx_Calibration_Start(&hadc1);//AD校准,单端输入
这边主要是adc配置部分,你想有一个单端输入 还是 差分输入,而h5会支持查分,所以这一部分需要说明,具体看下面
这边我只放一部分,stm32h5xx_hal_adc_ex.c你在这个文件即可找到,然后看一下函数就知道怎么用了
/**
* @brief Perform an ADC automatic self-calibration
* Calibration prerequisite: ADC must be disabled (execute this
* function before HAL_ADC_Start() or after HAL_ADC_Stop() ).
* @param hadc ADC handle
* @param SingleDiff Selection of single-ended or differential input
* This parameter can be one of the following values:
* @arg @ref ADC_SINGLE_ENDED Channel in mode input single ended
* @arg @ref ADC_DIFFERENTIAL_ENDED Channel in mode input differential ended
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef *hadc, uint32_t SingleDiff)
{
HAL_StatusTypeDef tmp_hal_status;
__IO uint32_t wait_loop_index = 0UL;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_SINGLE_DIFFERENTIAL(SingleDiff));
配置完之后,我们来看一下实物图片。
补充一个东西:因为我的ide出了点问题,暂时没办法烧录,还没解决,为了演示,这边教大家使用别的烧录方法,下载programmer,也就是下面这个,可以直接把编译文件放进去烧录
实物就是一个光照度计,然后这个模块会根据不同照度输出adc值,强的时候大,我们接线部分只需要把模拟输出部分接到单片机的adc上即可,具体实物图片和视频放在最后,这边补一下串口接收到的值。
可以看到一开始值很小,然后把手机手电筒凑上去之后值会变大。
详细的视频见下,拍了两个小视频,一个打开手电筒后,可以明显看到值会变大。
[localvideo]ab302feda5e272f571f35c34febdfbde[/localvideo]
[localvideo]35b4b1ea310824cff5cfa9e983957b19[/localvideo]
[localvideo]38aa1e32acde3217d67d41074e5d9770[/localvideo]
-
回复了主题帖:
【STM32 H533RE】测评三_串口屏和IIC测试
秦天qintian0303 发表于 2025-3-18 08:42
这个串口屏是哪家的?
最大7寸价格约200-300,小一点的一般100内
-
回复了主题帖:
【STM32 H533RE】测评三_串口屏和IIC测试
秦天qintian0303 发表于 2025-3-18 08:42
这个串口屏是哪家的?
陶晶驰的串口屏,如果要做显示的话,串口屏开发很快,我打限时类比赛的时候基本上为了快速做UI显示,都是直接拿串口屏开发,差不多一个小时就能做出想要的效果
- 2025-03-17
-
发表了主题帖:
【STM32 H533RE】测评三(补充)_IIC测试
本帖最后由 Zhao_kar 于 2025-3-17 20:58 编辑
【STM32 H533RE】测评三(补充)_IIC测试
备注:上一节单单演示HMI的配置花了比较多的篇幅,所以补一下IIC,这里就拿最简单的oled演示,后续的aht10也会用上,然后TTS模块本来说要演示,不过我觉得没什么必要,本质上就是一个printf就能解决的事。
一、oled库的准备
开发oled基本上标准库是最快的,但是实际上用hal开发也是没差,最后用的都是已经封装好的oled的库,这里不放了,反正网上到处都有,文章最后再补一下
原理方面不再本篇细说,这边只说运用和测试,只需要知道四根线,然后scl和sda两个数据线,两根供电线。
只需要知道函数怎么用,我会在代码部分说明
二、cubemx配置
这个也很简单,可以选择软件模拟,也就是IO配置,这边直接演示IIC的快速模式的配置。
只需要打开IIC,然后快速模式,最后设置一下时钟树和其他基础设置即可
三、文件配置和代码部分
1、文件配置
平时做开发都会自己留库文件,需要的时候直接调出来用即可,我是把之前存的直接拿过来用,新手去网上找相关文件即可,一般就三个
一个oledc一个oledh一个oledfonth,总之把c文件放到src里面,然后其他两个放在inc,或者新建文件夹,然后再导入,这些看习惯吧
注意,编辑完之后看你的hal库是哪个,比如我存的是f4的,拿过来用要改成h5的
2、代码开发
其实就是调库,这个真没什么难的,根据你需要的排版来使用,操作如下
1、先加入h文件
/* USER CODE BEGIN Includes */
#include "oled.h"
/* USER CODE END Includes */
2、初始化和其他配置,加在初始化部分函数就行
OLED_Init();
OLED_Clear();
3、接下来直接用,我在这里用到了如下函数
OLED_ShowString(0,0,"hello world",16);
OLED_ShowNum(0, 2, 12345, 5, 16); // 在(0,2)位置显示数字12345,占5位,16x16字体
OLED_ShowChar(64, 4, 'A', 16); // 在(64,4)位置显示字符'A',16x16字体
OLED_ShowCHinese(0, 6, 0); // 显示第一个汉字(需要 `Hzk` 字库数组)
HAL_Delay(1000);
OLED_On(); // OLED 全屏点亮测试
分别实现,第一行显示helloworld,然后第二行显示数字12345,然后第三行的靠右位置显示一个字符A,最后用hzk库的汉字,我这边随便放了一个,具体取模网上资料很多,不做说明。
测试完之后延时一下,做一个全屏的测试,显示如下
然后录一个小视频吧,显示效果也很简单,基本上会用这几个函数就能做基础显示了,如果需要60hz或者图像的还需要再深入学习一下。
[localvideo]99498ea060f4d04ed77986af7ca491e6[/localvideo]
oled的c
#include "oled.h"
#include "i2c.h"
#include "oledfont.h" //头文件
uint8_t CMD_Data[]={
0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,
0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,
0xD8, 0x30, 0x8D, 0x14, 0xAF}; //初始化命令
void WriteCmd(void)
{
uint8_t i = 0;
for(i=0; i<27; i++)
{
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,CMD_Data+i,1,0x100);
}
}
//向设备写控制命令
void OLED_WR_CMD(uint8_t cmd)
{
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}
//向设备写数据
void OLED_WR_DATA(uint8_t data)
{
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);
}
//初始化oled屏幕
void OLED_Init(void)
{
HAL_Delay(200);
WriteCmd();
}
//清屏
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
OLED_WR_CMD(0xb0+i);
OLED_WR_CMD (0x00);
OLED_WR_CMD (0x10);
for(n=0;n<128;n++)
OLED_WR_DATA(0);
}
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_CMD(0X8D); //SET DCDC命令
OLED_WR_CMD(0X14); //DCDC ON
OLED_WR_CMD(0XAF); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_CMD(0X8D); //SET DCDC命令
OLED_WR_CMD(0X10); //DCDC OFF
OLED_WR_CMD(0XAE); //DISPLAY OFF
}
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
OLED_WR_CMD(0xb0+y);
OLED_WR_CMD(((x&0xf0)>>4)|0x10);
OLED_WR_CMD(x&0x0f);
}
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);
} //更新显示
}
unsigned int oled_pow(uint8_t m,uint8_t n)
{
unsigned int result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2)
{
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);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
{
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++)
OLED_WR_DATA(F8X16[c*16+i]);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_DATA(F8X16[c*16+i+8]);
}
else {
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
OLED_WR_DATA(F6x8[c][i]);
}
}
//显示一个字符号串
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)
{
unsigned char j=0;
while (chr[j]!='\0')
{ OLED_ShowChar(x,y,chr[j],Char_Size);
x+=8;
if(x>120){x=0;y+=2;}
j++;
}
}
//显示汉字
//hzk 用取模软件得出的数组
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no)
{
uint8_t t,adder=0;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)
{
OLED_WR_DATA(Hzk[2*no][t]);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
OLED_WR_DATA(Hzk[2*no+1][t]);
adder+=1;
}
}
oled的h
#ifndef __OLED_H__
#define __OLED_H__
#include "stm32h5xx_hal.h"
///
#define OLED_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define GPIOx_OLED_PORT GPIOB
#define OLED_SCK_PIN GPIO_PIN_6
#define OLED_SCK_ON() HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SCK_PIN, GPIO_PIN_SET)
#define OLED_SCK_OFF() HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SCK_PIN, GPIO_PIN_RESET)
#define OLED_SCK_TOGGLE() HAL_GPIO_TogglePin(GPIOx_OLED_PORT, OLED_SCK_PIN)
#define OLED_SDA_PIN GPIO_PIN_7
#define OLED_SDA_ON() HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SDA_PIN, GPIO_PIN_SET)
#define OLED_SDA_OFF() HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SDA_PIN, GPIO_PIN_RESET)
#define OLED_SDA_TOGGLE() HAL_GPIO_TogglePin(GPIOx_OLED_PORT, OLED_SDA_PIN)
///
void WriteCmd(void);
void OLED_WR_CMD(uint8_t cmd);
void OLED_WR_DATA(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(uint8_t x, uint8_t y);
void OLED_On(void);
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size);
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size);
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no);
#endif
oledfonth
#ifndef __OLEDFONT_H__
#define __OLEDFONT_H__
#include "stm32h5xx_hal.h"
//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]=
{
{0x00,0x00,0x04,0x14,0x64,0x04,0x0C,0xB4,0x02,0x02,0x42,0x33,0x02,0x00,0x00,0x00},
{0x40,0x41,0x21,0x11,0x09,0x05,0x03,0xFF,0x03,0x05,0x09,0x11,0x21,0x41,0x40,0x00},/*"采",0*/
/* (16 X 16 , 宋体 )*/
{0x10,0x10,0xD0,0xFF,0x90,0x00,0x10,0x91,0x96,0x90,0xF0,0x90,0x94,0x93,0x10,0x00},
{0x04,0x03,0x00,0xFF,0x00,0x01,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x00},/*"样",1*/
/* (16 X 16 , 宋体 )*/
{0x00,0x80,0x60,0xF8,0x07,0x04,0xE4,0xA4,0xA4,0xBF,0xA4,0xA4,0xE4,0x04,0x00,0x00},
{0x01,0x00,0x00,0xFF,0x40,0x40,0x7F,0x4A,0x4A,0x4A,0x4A,0x4A,0x7F,0x40,0x40,0x00},/*"值",2*/
/* (16 X 16 , 宋体 )*/
{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00},
{0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00},/*"电",3*/
/* (16 X 16 , 宋体 )*/
{0x00,0x00,0xFE,0x02,0x82,0x82,0x82,0x82,0xFA,0x82,0x82,0x82,0x82,0x82,0x02,0x00},
{0x80,0x60,0x1F,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x44,0x58,0x40,0x40,0x00},/*"压",4*/
/* (16 X 16 , 宋体 )*/
{0x00,0x80,0x60,0xF8,0x07,0x04,0xE4,0xA4,0xA4,0xBF,0xA4,0xA4,0xE4,0x04,0x00,0x00},
{0x01,0x00,0x00,0xFF,0x40,0x40,0x7F,0x4A,0x4A,0x4A,0x4A,0x4A,0x7F,0x40,0x40,0x00},/*"值",5*/
/* (16 X 16 , 宋体 )*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",6*/
/* (16 X 16 , 宋体 )*/
};
#endif
-
发表了主题帖:
【STM32 H533RE】测评三_串口屏和IIC测试
本帖最后由 Zhao_kar 于 2025-3-17 17:37 编辑
【STM32 H533RE】测评三_串口屏和IIC测试
备注:本篇简单过一下串口屏的基础功能和基础配置,然后这个办卡有一个很有意思的地方,他把串口1的借口留了两个,所以可以实现单片机向串口屏交互的时候,同时跟pc端口的调试助手交互,平时基本上都是用串口屏自带的模拟来测试的,现在因为这个物理上的双接线,直接用起来还挺方便的,然后还有IIC的一个基础测试,串口屏部分主要讲如何新建工程,字库,如何选择控件,还有如何设置控件函数,以及单片机部分想在串口屏上显示参数的时候函数要怎么写。
一、TJC串口屏的软件基本使用
1、下载和更新就不讲了,新建工程这部分只需要知道自己的屏幕型号即可,横屏竖屏按照交互来,需要注意的地方只有供电问题,若遇上7寸的大屏,则需要外部供电,单片机供电基本上没办法支持,我这里图方便直接拿的ch340转串口模块直接供电的,这个看习惯。
如下图,基本上就能把工程建好了
然后刚开始用要先新建字库,有了的话可以自己调用,这边先简单过一遍字库
字库建完之后,可以开始对自己的屏幕进行布局,然后简单介绍一下几个基础的,比较常用的控件
主要是按钮控件,文本框显示控件,以及可以显示波形图的曲线控件。
然后布局部分就两点,右边属性框有xy和1wh可以输入,确定位置,wh确定高度,如下图
其他控件同理,这个不细说了,然后最后需要了解的是控件的一个固定参数,我先称之为标签吧,后面编程会用上
然后直接说一下如何使用,这里以按钮为例,点击的时候,他会有上图一样的两个事件,如按下和弹起,这里以基础串口发送为例
(官方自带补充,写代码会很方便,还有注释,会告诉你这个是输出什么类型的,如这个就是十六进制)
然后这里输入01,意味着按下按钮发送01,同理可操作按钮2
然后到波形控件和文本控件属于接受显示部分,你也可以把他当按钮,这个也是可以玩的,毕竟这是触摸的串口屏,我这里对波形控件加了一个03
最后只需要设置波特率即可,这个在初始化部分,点击一下空白处会弹出,如下,这里就是设置波特率
以上就是基础配置,然后就可以链接ch340,下载程序到串口屏里面了,需要等待一下时间,下载之前需要编译,然后可以调试一下,如下
下载这部分不放了,连接部分就rxtx互相联,这个不说了,下载之后如下图
二、单片机的串口屏配置补充(接下来就是串口屏配置)
1、cubemx的基操
如何配置时钟树,以及stlink什么的不说了,我这里配置了led2的PA5,还有串口1。
如下,PS:中断要打开哦
然后就是生产代码,然后就可以直接编辑了,补充一个地方,cubeide里面的勾选microlib上一节说过了,这里教一下如何配置函数
先说一下测试思路:
硬件接线部分为单片机的串口1连接到串口屏和ch340,然后340接电脑,以串口屏向单片机发送指令,单片机接受到指令后,进行反应,向串口1的设备发送数据,同时控制led
其中,1为发送文本66,令led关闭;2为开灯发送88;3为发送sin波形,并且开灯。
知道功能之后,就可以设计代码,详见如下:
//这部分为在usart部分添加函数
/* USER CODE BEGIN 1 */
#include <stdio.h>
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
HAL_UART_Receive(&huart2, &ch, 1, 0xffff);
return ch;
}
/* USER CODE END 1 */
//变量定义
/* USER CODE BEGIN PV */
uint8_t aRxBuffer;
uint8_t B=66;
uint8_t A=88;
double wave_sin1[140];
uint8_t wave_sin2[140];
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
//串口接受的回调函数
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
//回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
switch(aRxBuffer)
{
case 0x01:
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);//拉低特定引脚 初始高,所以灭灯
printf("t0.txt=\"%u \"\xff\xff\xff", B); //文本显示
} break;
case 0x02:
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//拉高特定引脚 初始低,所以亮灯
printf("t1.txt=\"%u \"\xff\xff\xff", A); //文本显示
} break;
case 0x03:
{
//printf("hello");
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//拉高特定引脚 初始低,所以亮灯
for(int i=0;i<140;i++)
{
wave_sin2[i]=(sin(2*3.14*i/140)+1)*1.0*100/2;//虚拟数据 2是int
wave_sin1[i]=sin(2*3.14*i/140);//虚拟数据wave 1是double
}
for(int i=0;i<140;i++)
{
printf("%d\n",wave_sin2[i]);//打印数据
//printf("add 2,0,%d\xff\xff\xff",wave_sin2[i]);
}
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);//循环使能,才能不断接收
}
}
点灯操作就不说了,没什么可说的
重点讲一下这个回调函数的使用,首先switch里面的ax那个变量,是回调函数接受串口收到的数据的,然后根据判断执行操作
然后到第一个,文本显示函数的使用,我们首先在串口屏里面看一下文本1的编号,即可知道如何使用
可以看到,有一个专属编号,也就是标签,为0,然后再看这个函数printf("t0.txt=\"%u \"\xff\xff\xff", B); 这意味着我们按下按钮1的时候,发送01到单片机的时候,单片机会对控件t0发送文本,然后把变量B的66发送过去,同理第二个也是一样,按下两个按钮之后会如图,对比之前的12,现在变成了66和88
然后波形控件部分如下,首先定义一个数组,存放波形,因为波形控件只能显示整数,所以我们要对sin处理一下,让他加1,然后因为波形控件的wh是140,所以我们的一切循环以140为基础,然后乘上50之后,波形就可以达到想要的效果,这个部分均可调整,然后是波形控件部分,add2 0这个,意思对编号2的控件发送数据,此时按下波形这个图,他就能接受到数据
for(int i=0;i<140;i++)
{
wave_sin2[i]=(sin(2*3.14*i/140)+1)*1.0*100/2;//虚拟数据 2是int
wave_sin1[i]=sin(2*3.14*i/140);//虚拟数据wave 1是double
}
for(int i=0;i<140;i++)
{
printf("%d\n",wave_sin2[i]);//打印数据
//printf("add 2,0,%d\xff\xff\xff",wave_sin2[i]);//(往ID为2的曲线控件添加波形)
}
如下图,可以看到是sin波。
然后在串口调试助手上也可以看到数据,如下(多按了几次)
然后按下按钮1和2时也能接收到printf的打印内容:
如下
最后放上个演示视频吧,然后IIC部分因为这篇篇幅多,我再写一篇简短点的补充一下
[localvideo]9daa2657c5402cc71b9b4c91eb530062[/localvideo]
- 2025-03-16
-
发表了主题帖:
【STM32 H533RE】测评八_温湿度传感器AHT10的测试
本帖最后由 Zhao_kar 于 2025-3-23 20:41 编辑
【STM32 H533RE】测评八_温湿度传感器AHT10的测试
备注:下一节补一个spi的测试,不用ld3320是因为最后LS要求不要扩展语音识别,只需要实现播报就行了,所以为了原先的计划,spi测试直接用oled做了,然后这个aht10是一个iic通信的传感器,会怎么驱动就可以直接读数据,读到数据之后如何去做处理,提高精度这部分,这里不讲了,本节就只是简单做一个aht10的测试,以及aht10的驱动是从网上学的,我也是第一次用这个传感器,但是感觉跟之前玩过的dh差不了多少。
一、aht10的原理和市面上常见温湿度传感器的选型区别
1、先说选型,目前你网上随便一找,最多的就是dht10这个,然后某陶上一搜也是就那几个常见的,其实都大差不差,具体选型原因如下:
首先目前市面上大部分湿度传感器在检测湿度的同时还可以检测温度,所以做温湿度检测的系统,只需要一个温湿度传感器,不必选用专门的温度传感器。常见的湿度传感器有DHT11、SHT11、AM2320、AHT10,因为设计要求温度范围应在-10度到50度,湿度范围应在20%到80%,所以无法选用DHT11,DHT温度范围只在0-50度,无法满足需求,而SHT11范围在-40度到125度,湿度范围在0到100%RH,性能符合要求,AM2320和AHT10也在范围上符合设计要求,考虑到AHT10价格更低,且参数合适,因此传感器部分选择AHT10。
原因如上,某陶买个aht10模块,也就一个指甲盖大,价格也很美丽,不到两位数还包邮,所以选择这个。
2、然后是原理部分
这一个部分多写一点iic的,毕竟之前oled没详细说明,对比常用的串口,串口两根线是全双工工作的,rxtx独立发信息,而iic表面上也是两根线,实际上一个是scl一个是sda,sda是传输数据的,这种是半双工模式,同时因为是这种半双工的工作状态,所以会有主机和从机,这属于一种总线,类似于上一节的ds18b20,简单来说就是一主机多从机的工作状态,只需要对相应的从机地址进行操作即可在这个总线内实现资源调度。然后scl是干什么的呢,对比串口就能明白了,之前设置串口屏的时候,不仅在单片机里面设定了通信的比特率,还在HMI里面设定了波特率,也就是说这个通信时钟是双方统一好的,而iic就不是,他是通过scl这个线来实现沟通的。
3、aht10部分,具体见文档,这里列举一些会在代码里面提到的
首先是供电,3.3v,文档说过的是1.8v到3.6v范围,同时我们要做一个延时,延时这部分先知道是20ms,具体怎么操作代码部分再说
然后是时序部分,这里了解一下即可
根据前面说的设备从机的地址,我们根据文档可以知道aht10的从机地址是0x38,如下
与此同时,因为传输的是一个字节,所以0x38是前七个bit,最后一个bit会需要知道是0还是1,这个决定读写操作。
但是设置地址是我们直接设置0x70,其实就是0111 0000,然后hal库会自动设置读写部分,所以宏定义部分设置70即可。
还有一个是触发测量指令,这个部分见文档,按照操作即可
其实就是0xac
最后是温湿度数据的读取,主要指导格式,读取时注意即可,也就是每组数据两个半字节,也就是20bit
最后是备注部分,代码里面延时75ms也是因为这个原因,如下:
然后还有一个tips,这里建议2s测一次,代码最后部分会说清楚,先放图在这里:
二、cubemx部分的配置
这个其实很简单,开个串口和一个IIC即可,跟之前配置oled没区别,如下,时钟树习惯性给72
三、代码部分
这里我把注释写在代码里面了,详情见下:
#include "aht10.h"
#define AHT10_ADDRESS 0x70 // AHT10 设备 I2C 地址
uint8_t readBuffer[6] = {0};
// 设备地址 0x38(7 位地址)+ 读/写位(1 位)=> 0x70
// AHT10 传输指令格式:
// - 设备地址 (7-bit) + 读/写位 (1-bit)
// - 初始化命令 0xE1
// - 读取温湿度命令 0xAC
/**
* @brief 初始化 AHT10 传感器
* @note 设备上电后需要最多 20ms 进入空闲状态,然后才能接受主机指令
*/
void AHT10_Init()
{
uint8_t readBuffer;
HAL_Delay(20); // 等待 AHT10 进入空闲状态
// 读取设备状态字节,检查设备是否已初始化
HAL_I2C_Master_Receive(&hi2c1, AHT10_ADDRESS, &readBuffer, 1, HAL_MAX_DELAY);
// 检查状态字节的 bit[3] (CAL_ENABLE),若未初始化,则发送初始化命令
if ((readBuffer & 0x08) == 0x00)
{
uint8_t sendBuffer[3] = {0xBE, 0x08, 0x00}; // 初始化命令
HAL_I2C_Master_Transmit(&hi2c1, AHT10_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
}
}
/**
* @brief 读取 AHT10 传感器的温度和湿度
* @param Temperature: 存储温度数据的变量指针
* @param Humidity: 存储湿度数据的变量指针
* @note 传感器测量时间约为 75ms,需要延时等待数据可用
*/
void AHT10_Read(float *Temperature, float *Humidity)
{
uint8_t sendBuffer[3] = {0xAC, 0x33, 0x00}; // 触发测量命令
uint8_t readBuffer[6] = {0}; // 存储读取的数据
// 发送测量指令
HAL_I2C_Master_Transmit(&hi2c1, AHT10_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
HAL_Delay(75); // 等待测量完成
// 读取 6 字节数据:状态字节 + 5 字节数据
HAL_I2C_Master_Receive(&hi2c1, AHT10_ADDRESS, readBuffer, 6, HAL_MAX_DELAY);
// 确保状态字节的 bit[7] (BUSY) 为 0,表示测量完成
if ((readBuffer[0] & 0x80) == 0x00)
{
uint32_t data = 0;
// 计算湿度值 (20-bit 数据)
data = ((uint32_t)readBuffer[3] >> 4) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);
*Humidity = data * 100.0f / (1 << 20); // 转换为百分比 RH
// 计算温度值 (20-bit 数据)
data = (((uint32_t)readBuffer[3] & 0x0F) << 16) + ((uint32_t)readBuffer[4] << 8) + (uint32_t)readBuffer[5];
*Temperature = data * 200.0f / (1 << 20) - 50; // 转换为摄氏度
}
}
h文件声明
#ifndef __DHT10_H__
#define __DHT10_H__
#include "i2c.h"
#include "main.h"
// 初始化AHT10
void AHT10_Init();
// 获取温度和湿度
void AHT10_Read(float *Temperature, float *Humidity);
#endif
串口初始化部分和声明省略,这里直接看主函数如何调用
/* USER CODE BEGIN 2 */
AHT10_Init(); // 初始化 AHT10
float temperature, humidity; // 温度和湿度变量
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
// 读取温湿度
AHT10_Read(&temperature, &humidity);
// 打印温湿度
printf("Temperature: %.1f DU\r\n", temperature);
printf("Humidity: %.1f %%\r\n", humidity);
// 延时 2 秒
HAL_Delay(2000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
为什么延时2s,已经在前面原理部分讲过了,本质上即为2s测一次温度
四、串口测试
最后把数据打印出来看看,对比今天的气温
可以看到串口打印的数据如下:
现在室温体感大约就是25度,然后我用手把传感器空捂住,他的湿度和温度会上升,尤其是湿度,湿度可以干到差不多80-90
若不采用空捂,用拇指接触传感器部分,则湿度不会很高,温度会上升,明显上升到30度
最后补上硬件连接图
- 2025-02-23
-
发表了主题帖:
【STM32 H533RE】测评二_环境配置和USART的测试
本帖最后由 Zhao_kar 于 2025-2-23 21:47 编辑
【STM32 H533RE】测评二_环境配置和USART的测试
备注:根据测评的计划,基本上已经把项目做完了,但是是用keil做的,于是抱着学习cubeide的心态,还是决定在后续的报告中用ide来实现,目前使用下来感觉ide的资料还是少一些,不过通过查阅官方资料都可以搞定,接下来就是尝试ide过程中的一些开发顺序,本文会从基础配置,到点灯的测试,cubeide自带的办卡配置和芯片配置等,最后还有usart的测试,下一篇应该会测串口屏,TTS模块,还有IIC的oled。
一、新环境的感觉
stm32cubeide搭建其实没什么说的,st官网下载,然后安装,按照流程就能走完,然后讲一下从哪下载H5的包,先在help、configuration tool里面点software,从里面找到所需芯片型号下载即可,基本上就没什么需要下载的了,唯一的槽点是现在所有的官方提供下载必须要登录,浏览器还会记录账号密码,ide老是需要我重新登陆,这一点比较麻烦,同时新建工程时,有一个firmware是存在c的,可以改一下路径,这个就不多说了。(图一官方下载。图二软件内的下载)
基本准备完成后,就可以开始建立工程了,选择file、new、stm32 project,然后会初始化,进入原先cubemx的选型界面,这里可以直接左边搜索,也可以收藏,方便之后用,点一下那个蓝色星星即可
这个是选择芯片来进行设计,因为官方板子是nucleo的,所以这一部分也可以直接选择板子,如图
两者不同只会在图形化配置那里有区别,其他的没差,下面我会补充一下两种方式的区别,接下来的工程名字和路径就不截图展示了
二、基础点个灯
首先是第一种方式,也就是有nucelo的操作,官方会自动选定led2,也就是PA5,一会第二种方式再补充如何看资料。
选好之后要配置时钟,也就是RCC,这个不像刚开始入门f1,stlink部分已经默认给你配置好了,如下
然后是时钟树,这个根据自己需求来,目前没什么需求,我习惯上都是直接取满加回车
然后是第三步,这里不用像keil去选其他的,勾选如下即可
然后就可以生成c文件了,直接c+s保存,然后他会弹出一个提示,问你以后要不要默认cs就自动更新,勾选就可以了,方便以后使用
生成之后就是如下main文件,一般会自己弹出,弹不出就去左边src找,如下
接下来就可以写代码了,这里要注意,因为nucelo官方自带库,所以点灯的时候不用像老方法去拉高拉低IO,直接按照如下函数即可
然后锤子编译,虫子下载,点右边这个都行,我一般右边这个
下载之后就可以观察板子了,接下来是第二种方法,没有nucleo的,基本上自己画板子都用这种的
然后是第二种,没选nucelo的,这部分需要先自己查资料,比如我们要驱动led,根据官方资料(如下),可以看到是PA5的口,各个led可以查手册
(查资料直接搜stm32h533re,然后去官方文档里面找,一般都很齐全,如下)
确定之后还是按照前面提到的,只不过这个时候看到的图形化配置是没有红色固定的,需要自己配置,然后配置RCC和IO的方法就不说了,跟之前一样,这里我设的高电平,所以没写代码会默认亮灯
时钟树和工程管理跟之前一样,然后代码部分用不了官方给的库,所以直接用hal的io配置led亮灭,如下
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);//拉低特定引脚
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//拉高特定引脚
HAL_Delay(1000);
}
配置完后就可以烧录了,烧录后就是如下视频所示
然后补充一个地方,stlinkV3要5V供电,我一开始识别不到,试了几条平时用的typec都不行,然后后面直接试的手机充电线,然后发现可以识别了,看了资料初步怀疑是电压问题,第一次用V3,我也不太清楚,然后更新驱动需要在help-stlink里面更新,如下图
(闪烁视频)[localvideo]2d0ea02402f0fe1efb30aca8c82111f6[/localvideo]
三、基本熟悉环境之后就是usart测试
这里就不分上面两种情况了,直接用的nucleo板子,其他步骤不变,只需要加一个usart的打开,设置如下
然后直接生成工程,这里先测试hal的函数,如下加上这两个,一个是16进制,一个是字符串,然后发送给串口部分,让PC串口助手查看参数
/* USER CODE BEGIN 2 */
uint8_t ch=0x41;
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
uint8_t aRxBuffer[]="hello eeworld\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, sizeof(aRxBuffer),0xFFFF);
/* USER CODE END 2 */
不解释这个函数了,后续发送一般都是重定向串口,这里展示接受到的图
然后重定向部分,一般都是usart写一个收发函数,主函数里面再调用,例如
#include <stdio.h>
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
然后keil里面有一个usb的microlib库,要勾选那个才能用,这个是我的一般习惯,但是ide里面没有这种东西,所以要按照别的方法来进行,这里附带一个链接,方法还是比较多的[STM32CubeIDE 二] printf重定向設置_cubeide printf 重定向-CSDN博客
自己上网找找也找得到,但是问题又来了,如果用的nucelo的板子,他已经默认把usart2作为printf函数了,所以此时有两种情况
1、不需要重定向,直接使用printf就可以调用
2、还是按照之前的方法,只不过要改一下官方的库,这个重定向也能用,也比较简单
演示一下自带的printf的串口发送,也就是while加了一下循环即可
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
printf("ch is %d\n",ch);//打印数据
HAL_Delay(1000);
}
综上,串口的基本测试就完成了,涉及串口的接受和中断部分,我再在下一节补充,这部分就先这样
- 2025-02-07
-
发表了主题帖:
【STM32 H533RE】测评一_开箱和基本介绍
本帖最后由 Zhao_kar 于 2025-2-7 22:39 编辑
【STM32 H533RE】测评一_开箱和基本介绍
备注:板子大概春节前两天收到,一直没时间写测评报告,现在过完年终于可以开始计划了,第一篇帖子就先从板子的开箱和基本介绍开始,其实stm32的环境配置哪都有,就不介绍了,后续打算用cubeide或者keil开发,这边主要是展示一下如何从官网去找板子的相关资料
一、开箱
板子收到之后是stm32的经典黄皮盒子和网格纸,可能是快递公司运输过程出了点小问题,我拿到板子的时候盒子已经裂开了,已经扔掉了,开箱部分就展示板子图片
1、板子包装图
2、板子实物图
二、基本介绍
根据官方给的资料,可以看到该板子不同于旧版的nucelo板子,这个是64引脚,然后stlink换成了typec的口,而且也是stlinkV3,观察实物,仔细看可以看出用的是F723的芯片,右上LD7是电源状态灯,LD1显示 ST-LINK 模块的通信状态,LD3是开发板的电源灯,下面是一个JP5,用于选择开发板电源的来源。可选择通过 USB 或其他外部电源输入,这里默认是stlink的5V供电。左上角的CN4是MIPI接口,然后JP6是3.3V的条线控制供电,JP2是测量电流的,左下角就是一个USB,大致介绍就是这样。根据官方特性,也可以快速了解,如下
最后补充一下,板子的引脚开发之类的,根据官方文档就能知道,如下
补充:下一篇就补充一下cubeide点灯,串口的使用,接着应该是ADC
- 2025-01-19
-
回复了主题帖:
【测评入围名单(最后1批)】年终回炉:FPGA、AI、高性能MCU、书籍等65个测品邀你来~
个人信息无误,确认可以完成测评计划
- 2024-05-30
-
发表了主题帖:
【2023 DigiKey大赛参与奖】开箱帖:STM32U5A5+F411 NUCLEO
因为下单比较晚,而且近期较忙,最近稍微闲一点,有时间发一下帖子,本次我是参与奖,然后因为金额不够买我想要的mpu,最后还是决定了入手一个stm32家的比较经典的f411和一个U5系列的板卡,下面为收到的开箱图,后续应该会玩一玩U5,看看有没有机会分享帖子吧,下次一定!
最后感谢下得捷电子和eeworld
虽然两个小板子,但是包装非常大
然后是外壳
最后是经典小碎纸
- 2024-05-07
-
发表了主题帖:
《深度学习与医学图像处理》阅读分享四——关键点检测
本帖最后由 Zhao_kar 于 2024-5-7 22:58 编辑
《深度学习与医学图像处理》阅读分享四——关键点检测
本节主讲关键点检测的模型
一、概念
关键点检测是计算机视觉领域的一种技术,用于在图像或视频中定位和识别特定对象或特征的位置。这些对象或特征可以是人脸、人体关节点、车辆、物体等等。关键点通常是图像中的特定位置,比如人脸关键点可能包括眼睛、鼻子、嘴巴等部位的位置。
关键点检测的目标是确定这些关键点在图像中的精确位置。它可以应用于许多应用场景,如人脸识别、姿态估计、手势识别、行人检测等。在人工智能和机器学习的帮助下,现代关键点检测算法能够在不同的环境和复杂的场景中准确地检测和定位这些关键点。
二、坐标关键点检测和热图关键点检测
1、坐标关键点检测:
特点:在坐标关键点检测中,通常直接输出每个关键点的准确坐标。这意味着检测器会返回一系列点的(x, y)坐标,表示图像中每个关键点的位置。
区别:相较于热图关键点检测,这种方法更加直接,输出结果更易理解。然而,它也需要更多的训练数据和更复杂的模型来学习关键点的准确位置。
2、热图关键点检测:
特点:热图关键点检测输出的是关键点位置的概率分布热图。这意味着对于每个关键点,检测器会生成一个与输入图像尺寸相同的热图,其中每个像素的值表示该像素处是关键点的概率。
区别:相对于坐标关键点检测,热图关键点检测更加灵活,因为它可以处理不同尺寸的输入图像,并且可以检测到关键点的模糊位置。此外,热图关键点检测还可以利用一些后处理技术来提高关键点检测的准确性。
综上,热图关键点模型效果更优,下面介绍几种基于热图的关键点模型
三、CPM
CPM指的是Convolutional Pose Machine(卷积姿势机器)。CPM是一种基于深度学习的方法,用于姿势估计和关键点检测。
CPM模型通常由多个卷积神经网络(CNN)阶段组成,每个阶段都负责在不同尺度上生成热图。第一个阶段处理输入图像,并生成初始热图,然后通过级联的阶段逐渐提高热图的分辨率和准确性。其中一个关键特点是通过级联的阶段来逐步提高姿势估计的精度。每个阶段都可以在之前阶段的输出基础上进行训练,使得模型能够逐渐细化关键点位置的估计。这种级联结构使得CPM在处理复杂姿势和场景时表现出色。
这里以书中给的图例为简单描述:一阶段中,图像先经过七个卷积层,三个池化层进行特征提取,P为关键点个数,然后在2阶段下,有两个输入,一个是第一阶段的特征输出,一个是原图像的特征提取,然后再通过五个卷积层进行融合和提取。详见下图
四、stack hourglass
Stacked Hourglass是一种基于卷积神经网络(CNN)的姿势估计方法,它采用了Hourglass网络结构的堆叠。每个Hourglass模块由对称的上采样和下采样层构成,有助于捕捉不同尺度的特征并提高姿势估计的准确性。通过堆叠多个Hourglass模块,Stacked Hourglass能够逐步细化关键点位置的估计,取得优异的姿势检测效果。
首先主要包括四个部分:下采样模块、沙漏模块、中间监督模块、关键点热力图
分别进行如下操作:降低图像分辨率,堆叠沙漏模块+引入中间监督模块,使得各个沙漏模块的输出均参与最终的损失计算,再利用计划函数将最后一个沙漏模块的输出结果转换为类别的概率值,生成关键点热力图。
补充(各个模块):
下采样模块是指在神经网络中的一种结构,用于将输入特征图的空间分辨率降低,同时增加特征图的通道数。这有助于提取更高级别的语义信息并减少计算量。通常通过池化层或者卷积层来实现。
沙漏模块是指沿着网络中间有多层的网络模块,形象地类似于一个沙漏,中间部分较窄,两边较宽。这种模块的设计目的是通过逐层的上采样和下采样来实现多尺度特征的融合,从而提高对目标的定位精度。
中间监督模块是指在网络的中间层添加监督信号,用于在训练过程中引导网络学习更好的特征表示。这种模块的存在有助于减轻梯度消失问题,并且可以加速训练过程。在姿势估计等任务中,中间监督模块通常用于在沙漏模块的不同层次上进行关键点位置的预测和监督。
-
发表了主题帖:
《深度学习与医学图像处理》阅读分享三——医学图像处理
本帖最后由 Zhao_kar 于 2024-5-7 22:10 编辑
《深度学习与医学图像处理》阅读分享——数据预处理部分
本节涉及数据预处理部分和数据增强部分,本节主要分享数据预处理部分,至于数据增强部分不做分享。
首先本书在数据预处理主要有如下几点:
插值
重采样
信号强度直方图
数据归一化
连通域分析和形态学方法
一、插值
首先结合实际环境和应用场景理解,如对图像进行旋转、放大的操作时,如一个2*2的四个像素,假如要放大成4*4的16像素,那么此时可以通过插值算法来进行操作,即我们进行放大操作时,因为会产生未知的像素点,而插值可以由原有的信息来进行预测。
两种常见插值方法:
1、最近邻插值法
这个比较简单,就是把距离最近的输入像素等于变换后的像素即可,所以计算速度很快,同时缺点也很明显,即为放大后的图像带有锯齿
2、双线性插值法
这里有一个公式,实际上可以结合图a来推,这个数学推导不难,总之了解有这么一个结论就可以了,而以此可以升为双线性插值法,相应的,效果会比较好,但是速度会慢一点。
详细效果对比见下图(可以看到图a是有明显的锯齿的)
二、重采样
这里涉及一个概念叫体素间距,场景为:实际上医学中人体部位的真实大小很重要,因此设备与协议之前的差别会导致不同的体素间距,因此要对体素间距进行重采样,保证体素个数可以反映实际成像大小。
这里有一个公式为:真实尺寸=体素个数*体素间距
所以为了保证真实尺寸不变,若增大图像的体素间距,则会导致个数变小,同时变小就出现了一中的问题,那么相应的还得考虑插值。
简单概括就是要改变体素间距和体素个数从而确保真实尺寸,实际上会结合插值和重采样。
三、直方图
说实在直方图这个比较简单,就是一个信号强度的体现,这里附上本书的一张图了解一下即可。
四、数据归一化
这个我觉得大部分做算法的应该都会用得上,比如在做信号处理 时,要对采集到的波形做归一化处理,从而去结合后续硬件软件等。
其实概念上就是消除量纲,本书有两个:
1、区间归一化
其实就是把最大值定位1,最小值定为0,其余参数除最大值,映射到0-1即可,这个自己写个函数就能实现
该方法对信号值敏感,对分布不敏感,适用于强度分布不固定的影像,如CT这种不同强度值含义固定的图像。
2、Z—score归一化
这个为映射到标准正态分布, 这个的特点和上面的方法相反,适用 于MR图像。
五、连通域分析和形态学方法
这里书中没有详细描述,只介绍了概念,这边就先只给出概念。
1、连通域一般是指图像中具有相同像素值且位置相邻的像素 点组成的图像区域。连通域分析是指将图像中的各个连通区域找出并标记。连通区域分析在图像分析处理的众多应用领域非常常用。连通区域分析处理的对象一般是一张二值化后的图像。
2、图像形态学也叫数学形态学,是指一系列处理图像形状特征的图像处理技术,是一门建立在格伦和拓扑学基础上的图像分析学科,是数学形态学图像处理的基本理论。其基本思想是利用一种特殊的结构元来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别