這一篇
esp8266與STM32連接,電腦通過(guò)STM32配置esp8266實(shí)現(xiàn)聯(lián)網(wǎng)發(fā)送數(shù)據(jù) 具體流程如下圖
2=
esp8266怎么和STM32連接(引腳連接)?
STM32CubeMx配置的usart2使用的PA2和PA3要與esp8266的TX和RX對(duì)應(yīng),但是得反過(guò)來(lái)接,要么根本發(fā)不出去,看來(lái)esp8266又印反了 3V3和EN得接到同一個(gè)3V上才可以,要不收到的老是errorSTM32使用USART和電腦相互傳輸數(shù)據(jù)?
將STM32產(chǎn)生的數(shù)據(jù)發(fā)送到電腦的串口調(diào)試助手 第一種方式: 使用UASRT傳輸只需要重新定義fputc()函數(shù),直接使用Printf函數(shù)就可以將字符串打印到電腦(即通過(guò)串口輸出到電腦) 第二種方式: 使用HAL庫(kù)中封裝好的UASART函數(shù) HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)也可以實(shí)現(xiàn)串口輸出 電腦要發(fā)送字符串給STM32,那么STM32怎么收到數(shù)據(jù),而且知道這個(gè)數(shù)據(jù)什么意思呢? 第一種方式(只能接收定長(zhǎng)字符串): HAL庫(kù)依舊有封裝好的函數(shù)HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout),但是使用這個(gè)函數(shù)有一個(gè)問(wèn)題,這個(gè)函數(shù)的額第三個(gè)參數(shù)是收到的字符串的大小,可是我都沒(méi)有發(fā)送,怎么提前把這個(gè)字符串的大小寫(xiě)入單片機(jī)呢? 其實(shí)問(wèn)題是STM32如何接收不定長(zhǎng)的字符串? 【STM32內(nèi)部產(chǎn)生的數(shù)據(jù)或者從傳感器中獲取的數(shù)據(jù),STM32如果要發(fā)送該數(shù)據(jù)可以直接使用sizeof獲得數(shù)據(jù)長(zhǎng)度作為第三個(gè)參數(shù),但是當(dāng)人為的發(fā)送給串口時(shí),由于提前燒入的程序如果要使用HAL庫(kù)的USART接收函數(shù)的話(huà),需要確定一個(gè)字符串長(zhǎng)度,那么這個(gè)程序就只能接收指定長(zhǎng)度的字符串了,那要如何實(shí)現(xiàn)不定長(zhǎng)也能接收呢?】 第二種方式: DMA+接收結(jié)束判斷。這接收結(jié)束判斷可以是字節(jié)的timeout,也可以是USART_IT_IDLE線(xiàn)路空閑的標(biāo)志等。這種方式對(duì)于需要整幀接收,且通信速度較快或需要占用cpu較少的情況 【詳細(xì)的處理方式可見(jiàn)串口USART 收發(fā)數(shù)據(jù)處理方式總結(jié)--DMA+USART+USART_Idle_Interrupt】那么如何配置呢?
既然是DMA和空閑接收中斷就需要設(shè)置DMA和UASRT的中斷(即在中斷處理函數(shù)中需要有DMA1 channel5 global interrupt和USART1 global interrupt) 如果要使用printf輸出到串口的話(huà),就需要重定義fputc函數(shù)(定義在usart.c中) 如果要用線(xiàn)路空閑來(lái)觸發(fā)中斷來(lái)結(jié)束接收的話(huà),需要有判斷線(xiàn)路是否空閑的函數(shù),這個(gè)函數(shù)最好還需要在結(jié)束接收時(shí)將收到的數(shù)據(jù)保存到自己定義的變量中那么如何實(shí)現(xiàn)不定長(zhǎng)接收呢,不還是得知道接受的字符串的長(zhǎng)度嗎?
是需要知道,這里使用一個(gè)結(jié)構(gòu)體來(lái)保存字符串和字符串的長(zhǎng)度以及一個(gè)標(biāo)記(用來(lái)表示一次接收完成,如果不放在結(jié)構(gòu)體里面,使用全局變量的話(huà)會(huì)比較麻煩) 具體的方法是這樣的:在一開(kāi)始接收的時(shí)候,將收到的字符串保存在結(jié)構(gòu)體中的字符串?dāng)?shù)組中,而函數(shù)要求的大小這個(gè)參數(shù)設(shè)置為比較大的數(shù)字(可以是一次接收數(shù)據(jù)長(zhǎng)度的最大值,這里是1024),在判斷線(xiàn)路是否空閑的函數(shù)中,當(dāng)線(xiàn)路空閑時(shí)(即一次接收完成時(shí)),將收到的字符串的長(zhǎng)度保存到這個(gè)結(jié)構(gòu)體中的字符串長(zhǎng)度變量中,這樣,當(dāng)需要將收到的字符串再次發(fā)出時(shí),就可以使用已知的長(zhǎng)度進(jìn)行發(fā)送了,由此實(shí)現(xiàn)了不定長(zhǎng)接收。 【其原理其實(shí)是用一個(gè)大空間去接收(看來(lái)接收空間夠大就行,不需要定長(zhǎng)接收),在接收完成時(shí)計(jì)算收到的數(shù)據(jù)長(zhǎng)度保存起來(lái)(和收到的數(shù)據(jù)要一一對(duì)應(yīng),這也是使用結(jié)構(gòu)體的好處),當(dāng)需要再次發(fā)送出去時(shí),就知道這個(gè)字符串的長(zhǎng)度了,就可以定長(zhǎng)發(fā)送了】 結(jié)構(gòu)體 #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函數(shù)中使用HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN); 開(kāi)始接收,接收的數(shù)據(jù)放到結(jié)構(gòu)體中,長(zhǎng)度為最大值 然后打開(kāi)中斷,__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);這個(gè)函數(shù)進(jìn)行中斷使能, 具體介紹: /** @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__) 之后是否需要延時(shí)防止接收不到或者防止其他錯(cuò)誤的發(fā)生不是很清楚。 在stm32f1xx_it.c的DMA和USART的中斷函數(shù)中并沒(méi)有需要重寫(xiě)的回調(diào)函數(shù) 在usart.c中實(shí)現(xiàn)處理空閑的函數(shù)添加到USART的中斷函數(shù)中,那么當(dāng)線(xiàn)路產(chǎn)生空閑時(shí),就會(huì)觸發(fā)一個(gè)中斷,這個(gè)空閑處理的函數(shù),就會(huì)開(kāi)始工作,先清空空閑標(biāo)志以允許繼續(xù)接收,然后使用HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)停止此次接收,接著獲得此次接收到的字符串的長(zhǎng)度(這里比較深入,有寄存器的問(wèn)題,不大理解),然后又調(diào)用了HAL_UART_Receive_DMA,這個(gè)應(yīng)該和取得的長(zhǎng)度是同一個(gè)結(jié)構(gòu)體,那么之前的HAL_UART_Receive_DMA又是再干什么呢?(或許是為了解決第一次的傳輸問(wèn)題,學(xué)的不夠深入,還需要學(xué)的再深入) 最后就可以使用獲得的長(zhǎng)度和字符串將收到的字符串發(fā)送出去了,這樣就實(shí)現(xiàn)了不定長(zhǎng)接收。 【問(wèn)題】在結(jié)構(gòu)體中定義的是一個(gè)uint8_t類(lèi)型的數(shù)組,那么可以按字符串輸出嗎? 可以, HAL_UART_Transmit(&huart1, UsartType.RX_pData, UsartType.RX_Size, 0xFFFF); printf(" %s ",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中實(shí)例化結(jié)構(gòu)體 /* USER CODE BEGIN 0 */ USART_RECEIVETYPE UsartType; /* USER CODE END 0 */ 在usart.h中定義結(jié)構(gòu)體 /* 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的中斷函數(shù)中添加 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函數(shù)中基本的初始化函數(shù)后添加 /* 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 */STM32如何給esp8266發(fā)送AT指令?
途徑就為通過(guò)串口 那么怎么使用串口, 是直接使用HAL庫(kù)封裝的相關(guān)函數(shù) 還是需要一些驅(qū)動(dòng)代碼 電腦通過(guò)串口與STM32交流,STM32通過(guò)串口與esp8266交流 既然上面實(shí)現(xiàn)了電腦與STM32使用USART相互傳輸數(shù)據(jù),即STM32可以接收電腦發(fā)來(lái)的不定長(zhǎng)數(shù)據(jù),那么STM32也能接收esp8266返回的不定長(zhǎng)數(shù)據(jù)(向esp8266發(fā)送不同的指令,返回消息不一樣,長(zhǎng)度也不一樣)對(duì)于接收esp8266返回的信息也使用DMA加空閑中斷的方式,那么向esp8266發(fā)送數(shù)據(jù)要怎么做呢?
上面的代碼已經(jīng)可以接收來(lái)自電腦的不定長(zhǎng)消息,然后再發(fā)給電腦,那么將這個(gè)消息直接發(fā)送給esp8266就可以了,兩個(gè)不同的串口有不同的實(shí)例,只需要指定好串口就可以向這個(gè)串口發(fā)送數(shù)據(jù)了?!就蝗挥X(jué)得自己寫(xiě)的好亂,沒(méi)有條理,得改】 其實(shí)具體的代碼就是在什么那個(gè)處理STM2與電腦使用USART通信的代碼上再增加一個(gè)STM與esp8266的USART交流流程就可以了,需要注意區(qū)分不同的串口,兩個(gè)流程的交匯點(diǎn)在main函數(shù)中,當(dāng)STM32收到電腦發(fā)來(lái)的不定長(zhǎng)信息后,通過(guò)空閑中斷處理函數(shù)獲得長(zhǎng)度,將該消息直接使用串口發(fā)送到連接esp8266的串口即可,如果STM32收到來(lái)自esp8266串口的消息,一樣使用DMA加空閑中斷的方式獲得來(lái)自esp8266的不定長(zhǎng)返回信息,在這里也是一樣通過(guò)這個(gè)串口的空閑中斷處理函數(shù)獲得返回信息的長(zhǎng)度,將這個(gè)返回信息發(fā)送給與電腦相連的串口就可以了,這樣就完成了通過(guò)STM32配置esp8266的整個(gè)流程。其意義是什么呢?
這樣STM32本身就可以使用串口將獲取的傳感器信息通過(guò)esp8266發(fā)送到指定服務(wù)器,實(shí)現(xiàn)了STM32的聯(lián)網(wǎng),一樣也實(shí)現(xiàn)了通過(guò)網(wǎng)絡(luò)向STM32發(fā)送指令控制傳感器的功能。
評(píng)論
查看更多