Initial import of STM32 IoT sensor node

This commit is contained in:
yzfh
2026-10-19 15:47:18 +08:00
commit a51794b022
100 changed files with 46274 additions and 0 deletions
+332
View File
@@ -0,0 +1,332 @@
#include <stdio.h>
#include <string.h>
#include "systick.h"
#include "queue.h"
#include "esp8266.h"
/* USART2管脚定义
TX PA2
RX PA3
*/
// 创建USART2的接收队列。
static struct queue usart2_rx_queue;
// 重置 Wifi 模块的传输模式为工作站模式,成功返回1,失败返回0.
int esp8266_reset_module(void)
{
char buf[100];
// 重置Wifi模块
esp8266_send_cmd("AT+RST");
delay_ms(1000);
delay_ms(1000);
esp8266_clear_read_buf();
// 设置Wifi的工作模式为 工作站模式
esp8266_send_cmd("AT+CWMODE=1");
if (esp8266_read_response(buf, sizeof(buf), 1000) == 0)
return 0;
if (strstr(buf, "OK"))
return 1;
return 0;
}
// ESP8266初始化
void esp8266_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// 初始化接收队列
queue_init(&usart2_rx_queue);
// 使能PA2和 PA3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 使能 USART2外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// 设置PA2 为发送管脚
// 复用推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 设置PA3 为接受管脚
// 悬空输入
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化 USART1控制器
USART_InitStruct.USART_BaudRate = 115200; // 设置波特率
USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长8bit
USART_InitStruct.USART_StopBits = USART_StopBits_1; // 停止位1bit
USART_InitStruct.USART_Parity = USART_Parity_No; // 校验位(无)
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发
USART_InitStruct.USART_HardwareFlowControl =
USART_HardwareFlowControl_None; // 硬件流控制(无)
USART_Init(USART2, &USART_InitStruct);
// 使能串口2
USART_Cmd(USART2, ENABLE);
// 初始化接收中断
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
// 清理中断标志位
USART_ClearFlag(USART2, USART_FLAG_TC);
NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; // 中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// 开启接收寄存器非空中断
// USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
if (0 == esp8266_reset_module())
printf("reset Wifi module Error!\r\n");
}
// 编写冲断处理函数
void USART2_IRQHandler(void)
{
uint8_t ch;
// 如果是接收寄存器非空中断,则读取数据
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
ch = USART_ReceiveData(USART2);
// 将接收到的字符放入接收队列,如果队列已满会丢掉此字符
queue_enqueue(&usart2_rx_queue, ch);
}
}
// 用于串口发送一个字节的数据
void usart2_put_char(uint8_t ch)
{
USART_SendData(USART2, ch); // 发送数据
// 等待发送数据完毕
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) != SET)
;
}
// ESP8266通过USART2发送字符串数据
void esp8266_send_string(const char *buf)
{
const char *pchar;
for (pchar = buf; *pchar; ++pchar)
usart2_put_char((uint8_t)*pchar);
}
// ESP8266通过USART2发送AT指令
void esp8266_send_cmd(const char *cmd)
{
esp8266_send_string(cmd);
esp8266_send_string("\r\n");
}
// 从USART2 读取相应字符串放入 buf,总等待时长timeout_ms毫秒ms,
// 直到timeout_ms耗尽为0才返回
int esp8266_read_response(char *buf, int buf_size, int timeout_ms)
{
int i = 0;
int ch = '\0';
// 等待接收数据,最大等待 timeout_ms 微妙
while (--timeout_ms)
{
if (queue_is_empty(&usart2_rx_queue))
delay_ms(1);
else
break;
}
if (timeout_ms == 0) // 超时返回
return 0;
// 接收数据
while (i < buf_size - 1 && timeout_ms > 0)
{
if (queue_is_empty(&usart2_rx_queue))
{
delay_ms(1); // 继续等待,直至timeout_ms为零
timeout_ms--;
}
else
{
queue_dequeue(&usart2_rx_queue, &ch);
buf[i] = ch;
i++;
}
}
buf[i] = '\0'; // 添加尾零后返回数据
// debug print for response
printf("esp8266_resp: %s\r\n", buf);
return i;
// for (i = 0; i < buf_size -1; i++) {
// queue_dequeue(&usart2_rx_queue, &ch);
// buf[i] = ch;
// if (queue_is_empty(&usart2_rx_queue))
// delay_ms(1);
// if (queue_is_empty(&usart2_rx_queue)) {
// i++;
// buf[i] = '\0';
// return i;
// }
// }
// return i;
}
// ESP8266 连接 Wifi,成功返回1,失败返回0
int esp8266_connect_wifi(const char *ssid, const char *passwd)
{
char buf[100];
// 拼接命令字符串
sprintf(buf, "AT+CWJAP=\"%s\",\"%s\"", ssid, passwd);
esp8266_clear_read_buf(); // 清空读缓冲。
esp8266_send_cmd(buf);
// WiFi 连接可能需要较长时间,延长超时到 15s
if (0 == esp8266_read_response(buf, sizeof(buf), 15000))
return 0;
if (strstr(buf, "OK") != NULL)
return 1;
// print returned response for debugging
printf("esp8266_connect_wifi failed resp: %s\r\n", buf);
return 0;
}
// ESP8266 作为客户端远程 TCP 连接。成功返回1,失败返回0
int esp8266_tcp_connect(const char *ip, uint16_t port)
{
char buf[100];
// 拼接命令字符串
sprintf(buf, "AT+CIPSTART=\"TCP\",\"%s\",%d", ip, port);
esp8266_clear_read_buf(); // 清空读缓冲。
esp8266_send_cmd(buf);
if (0 == esp8266_read_response(buf, sizeof(buf), 8000))
return 0;
// some firmwares may return "OK" or "ALREADY" or "ERROR"
if (strstr(buf, "OK") != NULL || strstr(buf, "ALREADY") != NULL)
return 1;
printf("esp8266_tcp_connect resp: %s\r\n", buf);
return 0;
}
// 关闭tcp 连接
void esp8266_tcp_close(void)
{
esp8266_send_cmd("AT+CIPCLOSE");
delay_ms(1000);
esp8266_clear_read_buf(); // 清空读缓冲。
}
// ESP8266 TCP 协议发送数据,返回写入的字节数,0表示失败
int esp8266_write(const char *data, uint16_t len)
{
char buf[100];
// 拼接命令字符串
sprintf(buf, "AT+CIPSEND=%d", len);
esp8266_clear_read_buf(); // 清空读缓冲。
esp8266_send_cmd(buf);
// wait for prompt '>' (and optionally OK). Allow longer timeout for some modules.
if (0 == esp8266_read_response(buf, sizeof(buf), 8000))
return 0;
// If there's no '>' in the response, but OK is present, try to read again shortly
if (strstr(buf, ">") == NULL) {
if (strstr(buf, "OK") != NULL) {
// try a short additional read to get the '>' prompt
if (0 == esp8266_read_response(buf, sizeof(buf), 2000) || strstr(buf, ">") == NULL) {
printf("esp8266_write: no '>' prompt after CIPSEND, resp: %s\r\n", buf);
return 0;
}
} else {
printf("esp8266_write: unexpected resp to CIPSEND: %s\r\n", buf);
return 0;
}
}
// send payload
esp8266_send_string(data);
// wait for SEND OK (some firmwares reply with SEND OK)
if (0 == esp8266_read_response(buf, sizeof(buf), 5000)) {
// no response, still consider write as attempted
return len;
}
if (strstr(buf, "SEND OK") != NULL || strstr(buf, "OK") != NULL) {
return len;
}
// unknown response, but we've attempted send
printf("esp8266_write: post-send resp: %s\r\n", buf);
return len;
}
// ESP8266 读取数据,返回读取的字节数
uint16_t esp8266_read(char *data, uint16_t buf_size)
{
// accumulate reads and search for +IPD, length:data pattern
char tmp[128];
char acc[512];
int acc_len = 0;
int total_timeout = 5000; // total wait up to 5s
int step = 200; // per-read timeout
acc[0] = '\0';
while (total_timeout > 0 && acc_len < (int)sizeof(acc) - 1)
{
int r = esp8266_read_response(tmp, sizeof(tmp), step);
if (r > 0)
{
// append
int copy = r < (int)sizeof(acc) - 1 - acc_len ? r : (int)sizeof(acc) - 1 - acc_len;
memcpy(acc + acc_len, tmp, copy);
acc_len += copy;
acc[acc_len] = '\0';
// debug
printf("esp8266_acc: %s\r\n", acc);
// search for +IPD,
char *pfind = strstr(acc, "+IPD,");
if (pfind)
{
pfind += 5; // move past +IPD,
// parse number until ':'
int len = 0;
while (*pfind && *pfind != ':' && len < 100000)
{
if (*pfind >= '0' && *pfind <= '9')
len = len * 10 + (*pfind - '0');
pfind++;
}
if (*pfind == ':')
{
pfind++; // data start
int copylen = len < (int)buf_size - 1 ? len : (int)buf_size - 1;
// ensure we have enough bytes in acc; if not, try to read more briefly
int available = (int)(acc + acc_len - pfind);
if (available < copylen)
{
// try one more short read
int r2 = esp8266_read_response(tmp, sizeof(tmp), 500);
if (r2 > 0)
{
int c = r2 < (int)sizeof(acc) - 1 - acc_len ? r2 : (int)sizeof(acc) - 1 - acc_len;
memcpy(acc + acc_len, tmp, c);
acc_len += c;
acc[acc_len] = '\0';
}
}
// copy payload
memcpy(data, pfind, copylen);
data[copylen] = '\0';
return (uint16_t)copylen;
}
}
}
else
{
total_timeout -= step;
}
}
return 0;
}
// ESP8266 清空读缓冲区
void esp8266_clear_read_buf(void)
{
queue_clear(&usart2_rx_queue);
}