esp8266實現STM32聯網(最簡單USART方法)
阿新 • • 發佈:2019-02-05
上一篇
esp8266怎麼配置
esp8266和USB轉TTL連線
esp8266簡單介紹
esp8266連線路由器
esp8266通過路由器連線在同一區域網中的電腦,建立TCP連線
esp8266使用串列埠傳送資料到電腦上的網路除錯助手
esp8266使用串列埠通過區域網傳送到電腦上自己寫的Java程式
esp8266的透傳模式
esp8266使用透傳模式連線到電腦的網路除錯助手
esp8266使用透傳模式連線到電腦上的java程式
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
這一篇
esp8266與STM32連線,電腦通過STM32配置esp8266實現聯網傳送資料
具體流程如下圖
- 1
- 2
- 3
esp8266怎麼和STM32連線(引腳連線)?
STM32CubeMx配置的usart2使用的PA2和PA3要與esp8266的TX和RX對應,但是得反過來接,要麼根本發不出去,看來esp8266又印反了
3V3和EN得接到同一個3V上才可以,要不收到的老是error
- 1
- 2
- 3
STM32使用USART和電腦相互傳輸資料?
將STM32產生的資料傳送到電腦的串列埠除錯助手 第一種方式: 使用UASRT傳輸只需要重新定義fputc()函式,直接使用Printf函式就可以將字串列印到電腦(即通過串列埠輸出到電腦) 第二種方式: 使用HAL庫中封裝好的UASART函式 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)也可以實現串列埠輸出 電腦要傳送字串給STM32,那麼STM32怎麼收到資料,而且知道這個資料什麼意思呢? 第一種方式(只能接收定長字串): HAL庫依舊有封裝好的函式HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout),但是使用這個函式有一個問題,這個函式的額第三個引數是收到的字串的大小,可是我都沒有傳送,怎麼提前把這個字串的大小寫入微控制器呢? 其實問題是STM32如何接收不定長的字串? 【STM32內部產生的資料或者從感測器中獲取的資料,STM32如果要傳送該資料可以直接使用sizeof獲得資料長度作為第三個引數,但是當人為的傳送給串列埠時,由於提前燒入的程式如果要使用HAL庫的USART接收函式的話,需要確定一個字串長度,那麼這個程式就只能接收指定長度的字串了,那要如何實現不定長也能接收呢?】 第二種方式: DMA+接收結束判斷。這接收結束判斷可以是位元組的timeout,也可以是USART_IT_IDLE線路空閒的標誌等。這種方式對於需要整幀接收,且通訊速度較快或需要佔用cpu較少的情況 【詳細的處理方式可見串列埠USART 收發資料處理方式總結--DMA+USART+USART_Idle_Interrupt】
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
那麼如何配置呢?
既然是DMA和空閒接收中斷就需要設定DMA和UASRT的中斷(即在中斷處理函式中需要有DMA1 channel5 global interrupt和USART1 global interrupt)
如果要使用printf輸出到串列埠的話,就需要重定義fputc函式(定義在usart.c中)
如果要用線路空閒來觸發中斷來結束接收的話,需要有判斷線路是否空閒的函式,這個函式最好還需要在結束接收時將收到的資料儲存到自己定義的變數中
- 1
- 2
- 3
- 4
- 5
- 6
那麼如何實現不定長接收呢,不還是得知道接受的字串的長度嗎?
是需要知道,這裡使用一個結構體來儲存字串和字串的長度以及一個標記(用來表示一次接收完成,如果不放在結構體裡面,使用全域性變數的話會比較麻煩)
具體的方法是這樣的:在一開始接收的時候,將收到的字串儲存在結構體中的字串陣列中,而函式要求的大小這個引數設定為比較大的數字(可以是一次接收資料長度的最大值,這裡是1024),在判斷線路是否空閒的函式中,當線路空閒時(即一次接收完成時),將收到的字串的長度儲存到這個結構體中的字串長度變數中,這樣,當需要將收到的字串再次發出時,就可以使用已知的長度進行傳送了,由此實現了不定長接收。
【其原理其實是用一個大空間去接收(看來接收空間夠大就行,不需要定長接收),在接收完成時計算收到的資料長度儲存起來(和收到的資料要一一對應,這也是使用結構體的好處),當需要再次傳送出去時,就知道這個字串的長度了,就可以定長髮送了】
結構體
#define RX_LEN 1024
typedef struct
{
uint8_t RX_flag:1; //IDLE receive flag
uint16_t RX_Size; //receive length
uint8_t RX_pData[RX_LEN]; //DMA receive buffer
}USART_RECEIVETYPE;
extern USART_RECEIVETYPE UsartType;
下面是程式的流程
首先在main函式中使用HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN); 開始接收,接收的資料放到結構體中,長度為最大值
然後開啟中斷,__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);這個函式進行中斷使能,
具體介紹:
/** @brief Enable the specified UART interrupt.
* @param __HANDLE__: specifies the UART Handle.
* UART Handle selects the USARTx or UARTy peripheral
* (USART,UART availability and x,y values depending on device).
* @param __INTERRUPT__: specifies the UART interrupt source to enable.
* This parameter can be one of the following values:
* @arg UART_IT_CTS: CTS change interrupt
* @arg UART_IT_LBD: LIN Break detection interrupt
* @arg UART_IT_TXE: Transmit Data Register empty interrupt
* @arg UART_IT_TC: Transmission complete interrupt
* @arg UART_IT_RXNE: Receive Data register not empty interrupt
* @arg UART_IT_IDLE: Idle line detection interrupt
* @arg UART_IT_PE: Parity Error interrupt
* @arg UART_IT_ERR: Error interrupt(Frame error, noise error, overrun error)
* @retval None
* */
#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)
之後是否需要延時防止接收不到或者防止其他錯誤的發生不是很清楚。
在stm32f1xx_it.c的DMA和USART的中斷函式中並沒有需要重寫的回撥函式
在usart.c中實現處理空閒的函式新增到USART的中斷函式中,那麼當線路產生空閒時,就會觸發一箇中斷,這個空閒處理的函式,就會開始工作,先清空空閒標誌以允許繼續接收,然後使用HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)停止此次接收,接著獲得此次接收到的字串的長度(這裡比較深入,有暫存器的問題,不大理解),然後又呼叫了HAL_UART_Receive_DMA,這個應該和取得的長度是同一個結構體,那麼之前的HAL_UART_Receive_DMA又是再幹什麼呢?(或許是為了解決第一次的傳輸問題,學的不夠深入,還需要學的再深入)
最後就可以使用獲得的長度和字串將收到的字串傳送出去了,這樣就實現了不定長接收。
【問題】在結構體中定義的是一個uint8_t型別的陣列,那麼可以按字串輸出嗎?
可以,
HAL_UART_Transmit(&huart1, UsartType.RX_pData, UsartType.RX_Size, 0xFFFF);
printf("\n%s\n",UsartType.RX_pData);
上面兩句一樣的效果
具體程式碼:
在usart.c中新增
/* USER CODE BEGIN 1 */
/**
* @brief Retargets the C library printf function to the USART.
*/
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/**
* @brief This function handles USART1 IDLE interrupt.
*/
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
uint32_t temp;
if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
temp = huart1.hdmarx->Instance->CNDTR;
UsartType.RX_Size = RX_LEN - temp;
UsartType.RX_flag=1;
HAL_UART_Receive_DMA(&huart1,UsartType.RX_pData,RX_LEN);
}
}
/* USER CODE END 1 */
在usart.c中例項化結構體
/* USER CODE BEGIN 0 */
USART_RECEIVETYPE UsartType;
/* USER CODE END 0 */
在usart.h中定義結構體
/* USER CODE BEGIN Private defines */
#define RX_LEN 1024
typedef struct
{
uint8_t RX_flag:1; //IDLE receive flag
uint16_t RX_Size; //receive length
uint8_t RX_pData[RX_LEN]; //DMA receive buffer
}USART_RECEIVETYPE;
extern USART_RECEIVETYPE UsartType;
/* USER CODE END Private defines */
在stm32f1xx_it.c的中斷函式中新增
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
UsartReceive_IDLE(&huart1);
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
在main.c中main函式中基本的初始化函式後新增
/* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_Delay(1000);
/* USER CODE END 2 */
- 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
STM32如何給esp8266傳送AT指令?
途徑就為通過串列埠
那麼怎麼使用串列埠,
是直接使用HAL庫封裝的相關函式
還是需要一些驅動程式碼
電腦通過串列埠與STM32交流,STM32通過串列埠與esp8266交流
既然上面實現了電腦與STM32使用USART相互傳輸資料,即STM32可以接收電腦發來的不定長資料,那麼STM32也能接收esp8266返回的不定長資料(向esp8266傳送不同的指令,返回訊息不一樣,長度也不一樣)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
對於接收esp8266返回的資訊也使用DMA加空閒中斷的方式,那麼向esp8266傳送資料要怎麼做呢?
上面的程式碼已經可以接收來自電腦的不定長訊息,然後再發給電腦,那麼將這個訊息直接傳送給esp8266就可以了,兩個不同的串列埠有不同的例項,只需要指定好串列埠就可以向這個串列埠傳送資料了。【突然覺得自己寫的好亂,沒有條理,得改】
其實具體的程式碼就是在什麼那個處理STM2與電腦使用USART通訊的程式碼上再增加一個STM與esp8266的USART交流流程就可以了,需要注意區分不同的串列埠,兩個流程的交匯點在main函式中,當STM32收到電腦發來的不定長資訊後,通過空閒中斷處理函式獲得長度,將該訊息直接使用串列埠傳送到連線esp8266的串列埠即可,如果STM32收到來自esp8266串列埠的訊息,一樣使用DMA加空閒中斷的方式獲得來自esp8266的不定長返回資訊,在這裡也是一樣通過這個串列埠的空閒中斷處理函式獲得返回資訊的長度,將這個返回資訊傳送給與電腦相連的串列埠就可以了,這樣就完成了通過STM32配置esp8266的整個流程。
- 1
- 2
- 3
其意義是什麼呢?
這樣STM32本身就可以使用串列埠將獲取的感測器資訊通過esp8266傳送到指定伺服器,實現了STM32的聯網,