#申请原创# @21小跑堂
5.UART通讯+SPI驱动LCD12864+温湿度读取
5.1UART通讯测试
UART在嵌入式领域应用的非常广泛,这块板子引出了一路串口接到了STLink的串口上,倒也省得再找USB转串口了,直接用这个测试一下串口功能
双击工程目录中的.ioc文件打开STM32CubeMX,找到USART3,可以看到默认的参数配置:波特率115200 数据位8 停止位1 无流控制和校验位
打开MDK,先写个按下按键通过串口发送数据的程序,代码示例
const char *uarttestdata = "NUCLEO-H563ZI 串口3测试\r\n";
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port,USER_BUTTON_Pin) == GPIO_PIN_SET)
{
HAL_UART_Transmit(&huart3,(uint8_t *)uarttestdata,strlen(uarttestdata),100);
}
}
烧录后用串口调试助手测试
接下来修改一下,开启中断,用串口将接收到的数据原样返回,默认的这里是Enable要改成Disable,不然发送的数据和返回的不一致
在STM32CubeMX中打开串口中断
点击生成代码,打开MDK,同样在串口初始化后也要手动开启中断接收
示例代码
uint8_t uartrxbuffer[1] = {0};
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART3)
{
HAL_UART_Transmit(huart,uartrxbuffer,1,100);
HAL_UART_Receive_IT(huart,uartrxbuffer,1);
}
}
如果想用空闲中断可以这么写
#define UARTRXBUFFERLEN 50
uint8_t uartrxbuffer[UARTRXBUFFERLEN] = {0};
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->RxEventType == HAL_UART_RXEVENT_IDLE)
{
HAL_UART_Transmit(huart,uartrxbuffer,Size,100);
HAL_UARTEx_ReceiveToIdle_IT(huart,uartrxbuffer,UARTRXBUFFERLEN);
}
}
串口初始化最后的开启中断接收也要换成HAL_UARTEx_ReceiveToIdle_IT(&huart3,uartrxbuffer,UARTRXBUFFERLEN);
运行效果
5.2SPI驱动LCD12864
SPI是一种高速的全双工同步的通信总线,需要至少SCK MOSI MISO三根线实现数据双向传输,可以通过片选线来实现对不同设备的访问
手上有个12864的LCD屏,用SPI驱动的,尝试用这块板子点亮一下,驱动这个屏需要用到5个IO:SCK MOSI CS RST A0都是输出模式,打开STM32CubeMX找到SPI,数据是单向传输的因此SPI配置成仅发送就行了
看一下用到的GPIO,默认的SCK是PA5 MOSI是PD7
但是原理图上这组SPI的MOSI是PB5
手动改一下,点击PB5选择SPI1_MOSI就行了
剩下的CS用PD14 RST用PB12 A0用PC7,都设置为输出,代码示例
YUYY_HS12864G18B_DEV_t hs12864_dev;
void lcd12864_init()
{
hs12864_dev.spix = &hspi1;
hs12864_dev.a0.gpio = LCD_A0_GPIO_Port;
hs12864_dev.a0.pin = LCD_A0_Pin;
hs12864_dev.cs.gpio = LCD_CS_GPIO_Port;
hs12864_dev.cs.pin = LCD_CS_Pin;
hs12864_dev.rst.gpio = LCD_RST_GPIO_Port;
hs12864_dev.rst.pin = LCD_RST_Pin;
yuyy_hs12864g18b_init(&hs12864_dev);
yuyy_hs12864g18b_clear_screen(&hs12864_dev);
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,0,0,(uint8_t *)"NUCLEO-H563ZI");
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,2,0,(uint8_t *)"SPI LCD Test");
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,0,(uint8_t *)"Code by yuyy1989");
yuyy_hs12864g18b_display_finish(&hs12864_dev);
}
显示效果
5.3读取DHT11温湿度
DHT11采用的是单总线通讯,即用一根数据线完成数据交换,MCU在通讯时需要切换IO的输入输出,对于这种情况可以使用GPIO的开漏输出来实现
开漏输出模式下GPIO可以强制拉低,但是需要拉高时需要借助外部的上拉电阻,而DHT11模块正好内置了10K的上拉电阻,这样作为输出时就能正常输出0或1,想要作为输入时只需要程序内输出1这样DHT11就能输出0或1,通过读取GPIO的实际电平就完成了数据的输入
打开STM32CubeMX,选择PG9作为DHT11的数据线,配置为开漏输出
按照手册的通讯规则写好获取温湿度的代码,通过LCD屏来显示温湿度
YUYY_DHT11_DEV_t dht11_dev;
void dht11_init()
{
dht11_dev.dat.gpio = DHT11_DAT_GPIO_Port;
dht11_dev.dat.pin = DHT11_DAT_Pin;
}
void usercode_loop(void)
{
float HumF,TemF;
char out[20];
uint8_t err=0,outlen;
yuyy_delay_ms(2000);
err = yuyy_dht11_readHT(&dht11_dev,&TemF,&HumF);
outlen = sprintf(out,"%d %.1f%% %.1f",err,HumF,TemF);
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,0,(uint8_t *)out);
yuyy_hs12864g18b_display_graphic_16x16(&hs12864_dev,0,4,8*outlen,(uint8_t *)test16x16temp);
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,8*(outlen+2),(uint8_t *)" ");
yuyy_hs12864g18b_display_finish(&hs12864_dev);
}
编译烧录查看运行效果
5.4I2C读取DHTC12温湿度
和上面的单总线不同,I2C属于两线式串行总线,使用一个时钟线和一个数据线,属于一主多从的总线结构,总线上的每个设备都有一个特定的设备地址,以区分同一I2C总线上的其他设备。这里用软件I2C来通讯,选用PF0为SDA PF1为SCL,在STM32CubeMX中将这两个IO设置为开漏输出,演示代码
YUYY_IIC_DEV_t iic_dev;
YUYY_SOFT_IIC_DEV_t siic_dev;
YUYY_DHTC12_DEV_t dhtc12_dev;
void softiic_init()
{
siic_dev.scl.gpio = SI2C_SCL_GPIO_Port;
siic_dev.scl.pin = SI2C_SCL_Pin;
siic_dev.sda.gpio = SI2C_SDA_GPIO_Port;
siic_dev.sda.pin = SI2C_SDA_Pin;
yuyy_soft_iic_init(&siic_dev);
iic_dev.iictype = YUYY_IIC_TYPE_SOFT;
iic_dev.siicx = &siic_dev;
}
void dhtc12_init()
{
dhtc12_dev.iicx = &iic_dev;
yuyy_dhtc12_init(&dhtc12_dev);
}
void usercode_loop(void)
{
float HumF,TemF;
char out[20];
uint8_t err=0,outlen;
yuyy_delay_ms(2000);
err = yuyy_dhtc12_readHT(&dhtc12_dev,&TemF,&HumF);
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,0,(uint8_t *)out);
yuyy_hs12864g18b_display_graphic_16x16(&hs12864_dev,0,4,8*outlen,(uint8_t *)test16x16temp);
yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,8*(outlen+2),(uint8_t *)" ");
yuyy_hs12864g18b_display_finish(&hs12864_dev);
}
运行效果
|