主要思路:

  1. 在标准库例子中的思路是,若收到串口空闲中断,则设置定时器。定时器时间到则认为串口接收完毕,置标志位。
  2. 在 HAL 库例子中的思路是,收到每一个字符都设置定时器,定时器时间到则认为串口接收完毕,置标志位。

本文假设的场景:

  1. 串口 1 连接电脑。printf 重写,输出至串口 1。详看:串口驱动程序之「发送数据」
  2. 串口 2 连接 ESP8266。ESP8266_Printf 函数重写 sprintf,输出到串口 2。
  3. 函数 uint8_t ESP8266_Cmd(uint8_t *cmd,uint8_t *expect_ack,uint16_t waittime) 用于发送 AT 命令,并将收到结果回显至电脑(解注释 printf)。

标准库

ESP8266 驱动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include "stm32f10x.h"                  // Device header
#include <stdarg.h> // sprintf
#include <stdio.h> // printf
#include <string.h>
#include "esp8266.h"
#include "timer.h"
#include "Systick.h"

#define USART2_MAX_SEND_LEN 600
uint8_t USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节

USART_Buffer ESP8266_Buffer;
void USART2_IRQHandler(void) {
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
if (ESP8266_Buffer.Length < (USART_RX_BUF_SIZE - 1))
ESP8266_Buffer.Body[ESP8266_Buffer.Length++] = (char)USART_ReceiveData(USART2);
}
if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) {
// ESP8266_Buffer.FinishFlag = 1;
ESP8266_Buffer.Body[ESP8266_Buffer.Length] = '\0';
volatile uint16_t temp; //编译器在优化代码时可能会移除那些看似不必要的重复读取或写入操作
// 清除串口空闲中断标志位
temp = USART2->SR;
temp = USART2->DR;

TIM_SetCounter(TIM2,0);//计数器清空
TIM_Cmd(TIM2,ENABLE);//使能定时器2
// 处理包的回调函数
// printf("USART_Buffer:\r\n%s",(const char*)ESP8266_Buffer.Body);
}
}


//定时器2中断服务程序
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//是更新中断
{
ESP8266_Buffer.FinishFlag = 1;
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIM2更新中断标志
TIM_Cmd(TIM2, DISABLE); //关闭TIM2
}

printf("Now Buffer:\r\n%s",(uint8_t*)ESP8266_Buffer.Body);
// printf("time2 yes\r\n");
}



// 默认115200
void ESP8266_Init(uint32_t baud)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

// 发送
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; // 复用推挽
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; // 发送
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
// 接收
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; // 上拉输入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3; // 接收
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);

USART_DeInit(USART2); //复位串口2
USART_InitTypeDef USART_InitStruture;
USART_InitStruture.USART_BaudRate=baud; // 波特率
USART_InitStruture.USART_HardwareFlowControl=USART_HardwareFlowControl_None;// 不使用流控制
USART_InitStruture.USART_Mode=USART_Mode_Tx | USART_Mode_Rx; // 同时开启发送和接收
USART_InitStruture.USART_Parity=USART_Parity_No; // 不需要校验位
USART_InitStruture.USART_StopBits=USART_StopBits_1;// 1 位停止位
USART_InitStruture.USART_WordLength=USART_WordLength_8b; // 字长
USART_Init(USART2,&USART_InitStruture);

// 接收-中断方式
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//USART_IT_RXNE一旦置1,将会向NVIC申请中断
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVIC_InitStructure);

USART_Cmd(USART2,ENABLE);

Timer_Init(0,20000-1,7200-1); //10ms中断
TIM_Cmd(TIM2,DISABLE); //关闭定时器2
}

void ESP8266_SendByte(uint8_t byte)
{
USART_SendData(USART2,byte); // 标志位自动清零
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);

// 不需要手动清零
}


/*
可以在main函数中使用printf,这将输出到指定串口中。
如果有多个串口需要输出。建议使用sprintf。再使用对应串口的ESP8266_SendString。
或者直接使用以下的封装函数
*/
void ESP8266_Printf(char *format,...)
{
// char String[100];
va_list arg;
va_start(arg,format);
vsprintf((char*)USART2_TX_BUF,format,arg);
va_end(arg);

u16 i,j;
i=strlen((const char*)USART2_TX_BUF); //此次发送数据的长度
// printf("length:%d,%s",i,(const char*)USART2_TX_BUF);
for(j=0;j<i;j++){
ESP8266_SendByte(USART2_TX_BUF[j]);
}
}



uint8_t ESP8266_Cmd(char *cmd,char *expect_ack,u16 waittime){
ESP8266_Printf("%s\r\n",cmd);
uint8_t chk=0;
while(waittime--) //等待倒计时
{
Delay_ms(10);
if(ESP8266_Buffer.FinishFlag)//接收到期待的应答结果
{

chk=ESP8266_Check_Str(ESP8266_Buffer.Body,expect_ack);
if(chk){
Delay_xms(20);
ESP8266_Buffer.Length =0 ;
ESP8266_Buffer.Body[ESP8266_Buffer.Length] = '\0';
break;//得到有效数据
}

ESP8266_Buffer.FinishFlag = 0; // 清除标志位
}
if(!waittime){
printf("Time Out!\r\n");
return 1; // Err
}
}
return 0; // OK
}

uint8_t ESP8266_Check_Str(char* check,char* espect){
char *strx=0;
strx=strstr((const char*)check,(const char*)espect);
if(strx)
return 1;
else
return 0;
}

HAL

ESP8266 驱动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "esp8266.h"

#include <string.h>
#include <stdarg.h> // sprintf
//#include "usart.h"
#include "cmsis_os.h"

uint8_t TxBuf[DATA_MAX];
uint8_t RxBuf[DATA_MAX];
uint8_t RxPoint = 0, RxData;
uint8_t UART2_Rx_flg=0;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart2)
{
__HAL_TIM_SET_COUNTER(&htim2,0);
if (RxPoint > DATA_MAX-1)
{
RxPoint = 0;
RxBuf[0] = 0;
UART2_Rx_flg = 0;
printf("Received too much data!\r\n");
return;
}

if(RxPoint == 0){
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_UPDATE);
HAL_TIM_Base_Start_IT(&htim2);
}

RxBuf[RxPoint++] = RxData;
HAL_UART_Receive_IT(&huart2, &RxData, 1);

}
}

void ESP8266_Printf(char *format,...)
{
va_list arg;
va_start(arg,format);
vsprintf((char*)TxBuf,format,arg);
va_end(arg);

HAL_UART_Transmit(&huart2,TxBuf,strlen((const char*)TxBuf),0xffff);
}

uint8_t ESP8266_Cmd(uint8_t *cmd,uint8_t *expect_ack,uint16_t waittime){
ESP8266_Printf("%s\r\n",cmd);
uint8_t chk=0;
while(waittime--) //等待倒计时
{
osDelay(10);
if(UART2_Rx_flg)//接收到期待的应答结果
{

chk=ESP8266_Check_Str(RxBuf,expect_ack);
if(chk){
osDelay(20);
// printf("Receive: %s\r\n",RxBuf);
RxBuf[0] = 0;
RxPoint = 0;
UART2_Rx_flg = 0; // 清除标志位
break;//得到有效数据
}
UART2_Rx_flg = 0; // 清除标志位
}

if(!waittime){
printf("Time Out!\r\n");
return 1; // Err
}
}
return 0; // OK
}



uint8_t ESP8266_Check_Str(uint8_t* check,uint8_t* espect){
char *strx=0;
strx=strstr((const char*)check,(const char*)espect);
if(strx)
return 1;
else
return 0;
}


main.c

1
2
3
4
5
6
7
8
int main(void)
{
HAL_UART_Receive_IT(&huart2, (uint8_t *)&RxData, 1); // 记得使能
while (1)
{
}

}

FreeRTOS.c:

1
2
3
4
5
6
7
8
9
10
11
// 定时器中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 1 */
if(htim->Instance == TIM2)
{
UART2_Rx_flg = 1;
HAL_TIM_Base_Stop_IT(&htim2);//关闭定时器
}
/* USER CODE END Callback 1 */
}

本文参考