摘要:為了可靠工作,在總線狀態切換時需要做適當延時,再進行數據收發。
????????基于ucosii實時操作系統的RS485通信,采用USART + DMA進行收發,
????????在RS-485通訊網絡中,節點中的串口控制器使用RX與TX信號線連接到收發器上,而收發器通過差分線連接到網絡總線,串口控制器與收發器之間一般使用TTL信號傳輸,收發器與總線則使用差分信號來傳輸。
????????發送數據時,串口控制器的TX信號經過收發器轉換成差分信號傳輸到總線上,
????????而接收數據時,收發器把總線上的差分信號轉化成TTL信號通過RX引腳傳輸到串口控制器中。
????????MCU管腳輸出TTL電平,TTL電平的意思是,當MCU管腳輸出0電平時,一般情況下電壓是0V,當MCU管腳輸出1電平時,電壓是5V。因TTL電平的是由一條信號線,一條地線產生,信號線上的干擾信號會跟隨有效信號傳送到接收端,使得有效信號受到干擾,485通訊實際上是把MCU出來的TTL電平通過硬件層的一個轉換器芯片進行轉換
????????RS-485通訊網絡的最大傳輸距離可達1200米,總線上可掛載128個通訊節點,而由于RS-485網絡只有一對差分信號線,它使用差分信號來表達邏輯,當AB兩線間的電壓差為-6V~-2V時表示邏輯1,當電壓差為+2V~+6V表示邏輯0,在同一時刻只能表達一個信號,所以它的通訊是半雙工形式的。
????????在單個實驗板中,作為串口控制器的STM32從USART外設引出TX和RX兩個引腳與RS-485收發器MAX485相連,收發器使用它的A和B引腳連接到RS-485總線網絡中。為了方便使用,我們每個實驗板引出的A和B之間都連接了1個120歐的電阻作為RS-485總線的端電阻,所以要注意如果要把實驗板作為一個普通節點連接到現有的RS-485總線時,是不應添加該電阻的!
????????MAX485芯片中有"RE"和"DE"兩個引腳,用于控制485芯片的收發工作狀態的,當RE引腳為低電平時,485芯片處于接收狀態,當DE引腳為高電平時芯片處于發送狀態。實驗板中使用了STM32的PD11直接連接到這兩個引腳上,所以通過控制PD11的輸出電平即可控制485的收發狀態。
?實驗板之間A與A連接,B與B連接即可。
?建立了5個任務
??任務名? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?優先級
?? ??? ??? ?APP_TASK_START_PRIO? ? ? ? ? ? ??2?? ???????? 主任務?? ? ??? ??? ?
??????????? Task_Com4_PRIO???????????????????? ? ? ? 4?? ??? ??? ?COM4通信任務
? ? ? ? ??
?? ??? ? 當然還包含了系統任務:
?? ??? ???? OS_TaskIdle????????????????? 空閑任務-----------------優先級最低
?? ??? ??? ?OS_TaskStat????????????????? 統計運行時間的任務-------優先級次低?
//建立主任務, 優先級最高 建立這個任務另外一個用途是為了以后使用統計任務os_err = OSTaskCreate((void (*) (void *)) App_TaskStart, (void *) 0, //指向任務代碼的指針 (void *) 0, //任務開始執行時,傳遞給任務的參數的指針 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //分配給任務的堆棧的棧頂指針 從頂向下遞減 (INT8U) APP_TASK_START_PRIO); //分配給任務的優先級
static void App_TaskStart(void* p_arg) { (void) p_arg //使能ucos 的統計任務 #if (OS_TASK_STAT_EN > 0) //----統計任務初始化函數 OSStatInit(); /* Determine CPU capacity. */ #endif //建立其他的任務 App_TaskCreate(); while (1) { //1秒一次循環 OSTimeDlyHMSM(0, 0,1, 0); } }
static void App_TaskCreate(void) { //CPU_INT08U os_err; //Com1_SEM=OSSemCreate(1); //建立串口4中斷的信號量 Com4_MBOX = OSMboxCreate((void *) 0); //建立串口4中斷的消息郵箱 //串口4接收及發送任務--------------------------------------------------------- OSTaskCreateExt(Task_Com4, //指向任務代碼的指針 (void *)0, //任務開始執行時,傳遞給任務的參數的指針 (OS_STK *)&Task_Com4Stk[Task_Com4_STK_SIZE-1],//分配給任務的堆棧的棧頂指針 從頂向下遞減 Task_Com4_PRIO, //分配給任務的優先級 Task_Com4_PRIO, //預備給以后版本的特殊標識符,在現行版本同任務優先級 (OS_STK *)&Task_Com4Stk[0], //指向任務堆棧棧底的指針,用于堆棧的檢驗 Task_Com4_STK_SIZE, //指定堆棧的容量,用于堆棧的檢驗 (void *)0, //指向用戶附加的數據域的指針,用來擴展任務的任務控制塊 OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR); //選項,指定是否允許堆棧檢驗,是否將堆棧清0,任務是否要進行浮點運算等等。 }
串口通信的任務:這里采用消息郵箱進行消息傳遞,
static void Task_Com4(void *p_arg){ INT8U err; int i; unsigned char * msg; (void)p_arg; while(1) { //OSSemPend(Com1_SEM,0,&err); //等待串口接收指令成功的信號量 msg=(unsigned char *)OSMboxPend(Com4_MBOX, 0,&err); //等待串口接收指令成功的郵箱信息 //輸出郵箱信息的前10個數據 if(msg != NULL) { for(i = 0; i < 2; i++) { G_u8Usart1SendBuf[i] = 0x10; } USART_DMA_SendStart(DMA2_Channel5, 2); memcpy(G_u8Usart1SendBuf, msg, 10); USART_DMA_SendStart(DMA2_Channel5, 10); } //DealWith_Data(pfifo); //處理數據 } }
? ? ? ? 以下是串口中斷函數,接收串口數據,當發現是完整的幀時,就調用OSMboxPost(Com4_MBOX,(void *)&msg);發送一個郵箱消息,進而那邊的串口任務從掛起到喚醒,執行相應的過程。
使用ringbuffer實現任意數據類型的FIFO處理接收數據,可以參考:stm32f0串口 DMA 空閑中斷接收——基于HAL庫(代碼篇)_噗噗bug博客-CSDN博客
void UART4_IRQHandler(void){ uint16_t t; unsigned int i; unsigned char msg[50]; OS_CPU_SR cpu_sr; OS_ENTER_CRITICAL() //保存全局中斷標志,關總中斷/ OSIntNesting++; OS_EXIT_CRITICAL(); //恢復全局中斷標志 if(USART_GetITStatus(UART4,USART_IT_IDLE) == SET) //檢查中斷是否發生 { RS485_TX_EN = 0; DMA_Cmd(DMA2_Channel3,DISABLE); //關閉DMA傳輸 DMA_ClearFlag( DMA2_FLAG_TC3 ); t = DMA_GetCurrDataCounter(DMA2_Channel3); //獲取剩余數量 //FIFO_Add(pfifo, G_u8Usart1RecvBuf, UART4_RECV_MAXLEN - t); //fifo數據保存 memcpy(msg, G_u8Usart1RecvBuf, UART4_RECV_MAXLEN - t); OSMboxPost(Com4_MBOX,(void *)&msg); DMA_SetCurrDataCounter(DMA2_Channel3,UART4_RECV_MAXLEN); //重新設置傳輸的數量 DMA_Cmd(DMA2_Channel3,ENABLE); //開啟DMA傳輸 USART_ReceiveData(UART4); //讀一次數據,不然會一直進中斷 USART_ClearFlag(UART4,USART_FLAG_IDLE); //清除串口中斷標志 } OSIntExit();}
void BSP_Init(void){ /* NVIC configuration */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); RS485_Config(); uart_init(9600); delay_init(); //延遲函數初始化}
注意:在485芯片的通信中,尤其要注意對485控制端DE的軟件編程。為了可靠工作,在485總線狀態切換時需要做適當延時,再進行數據收發。具體的做法是:
? ? ?在數據發送狀態下, ??先將控制端置“1”,延時1ms左右的時間,在發送有效的數據,一包數據發送結束后再延時1ms后,將控制端置“0”,這樣處理會使總線在狀態切換時,有一個穩定的工作過程。代碼中延遲10ms(參考:https://blog.csdn.net/yx_l128125/article/details/7914102)
#define RS485_TX_EN PAout(15) 設置RS485 mode控制, RX:0, TX:1void USART_DMA_SendStart(DMA_Channel_TypeDef *DMA_Streamx, u16 m_u16SendCnt) { USART_DMACmd(UART4, USART_DMAReq_Tx, ENABLE); RS485_TX_EN = 1; delay_ms(10); //延遲 DMA_Cmd(DMA_Streamx, DISABLE); delay_ms(10); //延遲 DMA_SetCurrDataCounter(DMA_Streamx, m_u16SendCnt); DMA_Cmd(DMA_Streamx, ENABLE); while(1) { if(DMA_GetFlagStatus(DMA2_FLAG_TC5)!=RESET)//μè′yí¨μà5′?ê?íê3é { DMA_ClearFlag(DMA2_FLAG_TC5);//??3yí¨μà5′?ê?íê3é±ê?? break; } } delay_ms(10); //延遲 RS485_TX_EN=0; }
int main(void){ unsigned char os_err; OSInit(); //硬件初始化 BSP_Init(); // FIFO 環型處理數據初始化 pfifo = &fifo; FIFO_Init(pfifo, aRxFIFOBuffer, sizeof(uint8_t), RXFIFOBUFFERSIZE); OSInit(); //先發送一段數據,可屏蔽 for(i = 0; i < 50; i++) { G_u8Usart1SendBuf[i] = 0x10 + i; } USART_DMA_SendStart(DMA2_Channel5, 50); os_err = OSTaskCreate((void (*) (void *)) App_TaskStart, (void *) 0, //指向任務代碼的指針 (void *) 0, //任務開始執行時,傳遞給任務的參數的指針 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //分配給任務的堆棧的棧頂指針 從頂向下遞減 (INT8U) APP_TASK_START_PRIO); //分配給任務的優先級 OSTimeSet(0); OSStart(); /* Start multitasking*/}
?參考:[stm32][ucos] 1、基于ucos操作系統的LED閃爍、串口通信簡單例程 - beautifulzzzz - 博客園
stm32f0串口 DMA 空閑中斷接收——基于HAL庫(代碼篇)_噗噗bug博客-CSDN博客
代碼:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121077.html
摘要:異步通信與同步通信異步通信異步通信是指通信的發送與接收設備使用各自的時鐘控制數據的發送和接收過程。同步通信同步通信時要建立發送方時鐘對接收方時鐘的直接控制,使雙方達到完全同步。配置串口設置為異步通信基礎參數波特率為。 ...
摘要:當單片機要接收數據的時候,控制為低電平,數據通過接收回來。檢測通過萬用表測量控制的引腳一直處于高電平,即使函數就單獨寫將該引腳為低電平,測量出來還是高電平。 一、問題: 問題現象:在進行RS485操作時,發現接收時而進時而不進中斷: 將485的AB輸出腳直接與串口的TX,RX對接發現串...
摘要:基于的移植教程可以看這里二介紹是一種用于嵌入式應用的圖形支持軟件。適用于使用任何控制和的任何尺寸的物理和虛擬顯示。一個層,稱作驅動程序,包含了對的全部訪問。并在主函數里加入下面的代碼,測試移植是否成功。 一、環境介紹 keil:? ? 5.25 MCU:? STM32F103ZET6 UCG...
摘要:一說明本庫基于編譯,其他的內核也支持,采用串口和模組通信。使用時添加文件到工程中,頭文件引用即可。此外,需要外部實現模組的復位操作,一般是對管腳拉高一段時間,復位函數需要指定函數為。四實例以下為使用的庫,實現對接自建。 一、說明 本lib庫基于STM32F407編譯,其他的cortexM4內...
摘要:文章目錄一原理二實現顯示中文滾動顯示顯示字符串讀取溫濕度顯示溫濕度三結果開機顯示歡迎信息循環讀取溫濕度以及滾動顯示我的四總結五參考六源碼一原理的定義就是串行外圍設備接口。 ...
閱讀 2380·2021-10-09 09:41
閱讀 3172·2021-09-26 09:46
閱讀 834·2021-09-03 10:34
閱讀 3150·2021-08-11 11:22
閱讀 3364·2019-08-30 14:12
閱讀 710·2019-08-26 11:34
閱讀 3343·2019-08-26 11:00
閱讀 1749·2019-08-26 10:26