1.简介
用stm32的串口通信与esp01s连接,通过esp01s发送AT指令,连接心知天气,获取温度和时间,并在1.8寸的lcd屏幕上进行显示。
2.串口和esp01s
使用函数发送数据
HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
修改中断接收数据,这里定义了一个数组buf1进行接收,也可以使用DMA。
uint8_t buf1[300];
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) == SET) {
__HAL_UART_CLEAR_IDLEFLAG(&huart1); // 清除空闲中断标志
// 还原缓冲区
huart1.RxXferCount = sizeof(buf1);
huart1.pRxBuffPtr = buf1;
// 重新启动中断接收
HAL_UART_Receive_IT(&huart1, buf1, sizeof(buf1));
return;
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
3.esp01s的at指令
通过上面的串口发送如下指令,进行连接。
char mode[] = "AT+CWMODE=1\r\n"; //设置STA模式
char A_spots[] = "AT+CWJAP=\"WiFi名称\",\"密码\"\r\n"; //连接wifi
char startTCP[]= "AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80\r\n"; //连接心知服务器
char data2[]= "AT+CIPSEND=114\r\n"; //开启数据发送
char data3[]= "GET https://api.seniverse.com/v3/weather/now.json?key=你的密钥&location=地址&language=en&unit=c\r\n";//发送API访问
需要注意以下几点。
1.发送后要有延迟,等待at指令返回。可以将其显示在lcd上。
HAL_Delay(2000);
LCD_ShowString(1, 1, (const uint8_t *)buf1, 0xFFFF, 0x0000, 12, 0);
memset(buf1, 0, sizeof(buf1)); //清空buf1
2.这里我用的是英文,因为后面返回中文的话会显示乱码。可修改对应en的位置改变语言。
char data3[]= "GET https://api.seniverse.com/v3/weather/now.json?key=SSvKGCGFa4n0Ej_1C&location=37.90:113.65&language=en&unit=c\r\n";//发送API访问
开启数据传输
AT+CIPSEND=?,等于的内容是你要发送的字符串长度。我的esp01s不能发送不定长的。
4.LCD的显示
我用的是修改的中景园给的1.8寸spi的代码,CubeMx上没有开启spi,是开了5个输出。直接用hal库函数替换了原先的标准库函数就可以了。
// LCD 控制引脚
#define LCD_SCLK_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET) // SCL = SCLK
#define LCD_SCLK_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET)
#define LCD_MOSI_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET) // SDA = MOSI
#define LCD_MOSI_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)
#define LCD_RES_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET) // RES
#define LCD_RES_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define LCD_DC_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET) // DC
#define LCD_DC_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET)
#define LCD_CS_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET) // CS
#define LCD_CS_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET)
#define LCD_BLK_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET) // BLK
#define LCD_BLK_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET)
5.提取返回的内容
用了一个提取内容的函数。
void displayWeatherInfo(const char *json_str) { //提取内容
char text[20] = {0};
char code[10] = {0};
char temperature[10] = {0};
// 提取text字段
const char *text_key = "\"text\":\"";
char *text_start = strstr(json_str, text_key);
if (text_start != NULL) {
text_start += strlen(text_key);
char *text_end = strchr(text_start, '"');
if (text_end != NULL) {
strncpy(text, text_start, text_end - text_start);
}
}
// 提取code字段
const char *code_key = "\"code\":\"";
char *code_start = strstr(json_str, code_key);
if (code_start != NULL) {
code_start += strlen(code_key);
char *code_end = strchr(code_start, '"');
if (code_end != NULL) {
strncpy(code, code_start, code_end - code_start);
}
}
// 提取temperature字段
const char *temperature_key = "\"temperature\":\"";
char *temperature_start = strstr(json_str, temperature_key);
if (temperature_start != NULL) {
temperature_start += strlen(temperature_key);
char *temperature_end = strchr(temperature_start, '"');
if (temperature_end != NULL) {
strncpy(temperature, temperature_start, temperature_end - temperature_start);
}
}
// 在LCD上显示内容
LCD_Fill(0, 0, LCD_W, 16, YELLOW);//指定区域填充颜色
LCD_ShowString(10, 20, (const uint8_t *)text, 0xFFFF, 0x0000, 32, 0); // 显示text
LCD_ShowString(50, 50, (const uint8_t *)code, 0xFFFF, 0x0000, 32, 0); // 显示code
LCD_ShowString(80, 60, (const uint8_t *)temperature, 0xFFFF, 0x0000, 32, 0); // 显示temperature
}
6.为什么不用json解析
因为我试了很多次都解析不了,即便删除了AT返回指令的开头和结尾都不行。
7.最终效果
因为准备学lvgl的界面,所以暂时不去美化界面了。