摘要:為了可靠工作,在總線狀態(tài)切換時需要做適當延時,再進行數(shù)據(jù)收發(fā)。
????????基于ucosii實時操作系統(tǒng)的RS485通信,采用USART + DMA進行收發(fā),
????????在RS-485通訊網(wǎng)絡中,節(jié)點中的串口控制器使用RX與TX信號線連接到收發(fā)器上,而收發(fā)器通過差分線連接到網(wǎng)絡總線,串口控制器與收發(fā)器之間一般使用TTL信號傳輸,收發(fā)器與總線則使用差分信號來傳輸。
????????發(fā)送數(shù)據(jù)時,串口控制器的TX信號經(jīng)過收發(fā)器轉換成差分信號傳輸?shù)娇偩€上,
????????而接收數(shù)據(jù)時,收發(fā)器把總線上的差分信號轉化成TTL信號通過RX引腳傳輸?shù)酱诳刂破髦小?/span>
????????MCU管腳輸出TTL電平,TTL電平的意思是,當MCU管腳輸出0電平時,一般情況下電壓是0V,當MCU管腳輸出1電平時,電壓是5V。因TTL電平的是由一條信號線,一條地線產(chǎn)生,信號線上的干擾信號會跟隨有效信號傳送到接收端,使得有效信號受到干擾,485通訊實際上是把MCU出來的TTL電平通過硬件層的一個轉換器芯片進行轉換
????????RS-485通訊網(wǎng)絡的最大傳輸距離可達1200米,總線上可掛載128個通訊節(jié)點,而由于RS-485網(wǎng)絡只有一對差分信號線,它使用差分信號來表達邏輯,當AB兩線間的電壓差為-6V~-2V時表示邏輯1,當電壓差為+2V~+6V表示邏輯0,在同一時刻只能表達一個信號,所以它的通訊是半雙工形式的。
????????在單個實驗板中,作為串口控制器的STM32從USART外設引出TX和RX兩個引腳與RS-485收發(fā)器MAX485相連,收發(fā)器使用它的A和B引腳連接到RS-485總線網(wǎng)絡中。為了方便使用,我們每個實驗板引出的A和B之間都連接了1個120歐的電阻作為RS-485總線的端電阻,所以要注意如果要把實驗板作為一個普通節(jié)點連接到現(xiàn)有的RS-485總線時,是不應添加該電阻的!
????????MAX485芯片中有"RE"和"DE"兩個引腳,用于控制485芯片的收發(fā)工作狀態(tài)的,當RE引腳為低電平時,485芯片處于接收狀態(tài),當DE引腳為高電平時芯片處于發(fā)送狀態(tài)。實驗板中使用了STM32的PD11直接連接到這兩個引腳上,所以通過控制PD11的輸出電平即可控制485的收發(fā)狀態(tài)。
?實驗板之間A與A連接,B與B連接即可。
?建立了5個任務
??任務名? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?優(yōu)先級
?? ??? ??? ?APP_TASK_START_PRIO? ? ? ? ? ? ??2?? ???????? 主任務?? ? ??? ??? ?
??????????? Task_Com4_PRIO???????????????????? ? ? ? 4?? ??? ??? ?COM4通信任務
? ? ? ? ??
?? ??? ? 當然還包含了系統(tǒng)任務:
?? ??? ???? OS_TaskIdle????????????????? 空閑任務-----------------優(yōu)先級最低
?? ??? ??? ?OS_TaskStat????????????????? 統(tǒng)計運行時間的任務-------優(yōu)先級次低?
//建立主任務, 優(yōu)先級最高 建立這個任務另外一個用途是為了以后使用統(tǒng)計任務os_err = OSTaskCreate((void (*) (void *)) App_TaskStart, (void *) 0, //指向任務代碼的指針 (void *) 0, //任務開始執(zhí)行時,傳遞給任務的參數(shù)的指針 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //分配給任務的堆棧的棧頂指針 從頂向下遞減 (INT8U) APP_TASK_START_PRIO); //分配給任務的優(yōu)先級
static void App_TaskStart(void* p_arg) { (void) p_arg //使能ucos 的統(tǒng)計任務 #if (OS_TASK_STAT_EN > 0) //----統(tǒng)計任務初始化函數(shù) OSStatInit(); /* Determine CPU capacity. */ #endif //建立其他的任務 App_TaskCreate(); while (1) { //1秒一次循環(huán) 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接收及發(fā)送任務--------------------------------------------------------- OSTaskCreateExt(Task_Com4, //指向任務代碼的指針 (void *)0, //任務開始執(zhí)行時,傳遞給任務的參數(shù)的指針 (OS_STK *)&Task_Com4Stk[Task_Com4_STK_SIZE-1],//分配給任務的堆棧的棧頂指針 從頂向下遞減 Task_Com4_PRIO, //分配給任務的優(yōu)先級 Task_Com4_PRIO, //預備給以后版本的特殊標識符,在現(xiàn)行版本同任務優(yōu)先級 (OS_STK *)&Task_Com4Stk[0], //指向任務堆棧棧底的指針,用于堆棧的檢驗 Task_Com4_STK_SIZE, //指定堆棧的容量,用于堆棧的檢驗 (void *)0, //指向用戶附加的數(shù)據(jù)域的指針,用來擴展任務的任務控制塊 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個數(shù)據(jù) 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); //處理數(shù)據(jù) } }
? ? ? ? 以下是串口中斷函數(shù),接收串口數(shù)據(jù),當發(fā)現(xiàn)是完整的幀時,就調用OSMboxPost(Com4_MBOX,(void *)&msg);發(fā)送一個郵箱消息,進而那邊的串口任務從掛起到喚醒,執(zhí)行相應的過程。
使用ringbuffer實現(xiàn)任意數(shù)據(jù)類型的FIFO處理接收數(shù)據(jù),可以參考: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) //檢查中斷是否發(fā)生 { RS485_TX_EN = 0; DMA_Cmd(DMA2_Channel3,DISABLE); //關閉DMA傳輸 DMA_ClearFlag( DMA2_FLAG_TC3 ); t = DMA_GetCurrDataCounter(DMA2_Channel3); //獲取剩余數(shù)量 //FIFO_Add(pfifo, G_u8Usart1RecvBuf, UART4_RECV_MAXLEN - t); //fifo數(shù)據(jù)保存 memcpy(msg, G_u8Usart1RecvBuf, UART4_RECV_MAXLEN - t); OSMboxPost(Com4_MBOX,(void *)&msg); DMA_SetCurrDataCounter(DMA2_Channel3,UART4_RECV_MAXLEN); //重新設置傳輸?shù)臄?shù)量 DMA_Cmd(DMA2_Channel3,ENABLE); //開啟DMA傳輸 USART_ReceiveData(UART4); //讀一次數(shù)據(jù),不然會一直進中斷 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(); //延遲函數(shù)初始化}
注意:在485芯片的通信中,尤其要注意對485控制端DE的軟件編程。為了可靠工作,在485總線狀態(tài)切換時需要做適當延時,再進行數(shù)據(jù)收發(fā)。具體的做法是:
? ? ?在數(shù)據(jù)發(fā)送狀態(tài)下, ??先將控制端置“1”,延時1ms左右的時間,在發(fā)送有效的數(shù)據(jù),一包數(shù)據(jù)發(fā)送結束后再延時1ms后,將控制端置“0”,這樣處理會使總線在狀態(tài)切換時,有一個穩(wěn)定的工作過程。代碼中延遲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 環(huán)型處理數(shù)據(jù)初始化 pfifo = &fifo; FIFO_Init(pfifo, aRxFIFOBuffer, sizeof(uint8_t), RXFIFOBUFFERSIZE); OSInit(); //先發(fā)送一段數(shù)據(jù),可屏蔽 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, //任務開始執(zhí)行時,傳遞給任務的參數(shù)的指針 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], //分配給任務的堆棧的棧頂指針 從頂向下遞減 (INT8U) APP_TASK_START_PRIO); //分配給任務的優(yōu)先級 OSTimeSet(0); OSStart(); /* Start multitasking*/}
?參考:[stm32][ucos] 1、基于ucos操作系統(tǒng)的LED閃爍、串口通信簡單例程 - beautifulzzzz - 博客園
stm32f0串口 DMA 空閑中斷接收——基于HAL庫(代碼篇)_噗噗bug博客-CSDN博客
代碼:
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/121077.html
摘要:異步通信與同步通信異步通信異步通信是指通信的發(fā)送與接收設備使用各自的時鐘控制數(shù)據(jù)的發(fā)送和接收過程。同步通信同步通信時要建立發(fā)送方時鐘對接收方時鐘的直接控制,使雙方達到完全同步。配置串口設置為異步通信基礎參數(shù)波特率為。 ...
摘要:當單片機要接收數(shù)據(jù)的時候,控制為低電平,數(shù)據(jù)通過接收回來。檢測通過萬用表測量控制的引腳一直處于高電平,即使函數(shù)就單獨寫將該引腳為低電平,測量出來還是高電平。 一、問題: 問題現(xiàn)象:在進行RS485操作時,發(fā)現(xiàn)接收時而進時而不進中斷: 將485的AB輸出腳直接與串口的TX,RX對接發(fā)現(xiàn)串...
摘要:基于的移植教程可以看這里二介紹是一種用于嵌入式應用的圖形支持軟件。適用于使用任何控制和的任何尺寸的物理和虛擬顯示。一個層,稱作驅動程序,包含了對的全部訪問。并在主函數(shù)里加入下面的代碼,測試移植是否成功。 一、環(huán)境介紹 keil:? ? 5.25 MCU:? STM32F103ZET6 UCG...
摘要:一說明本庫基于編譯,其他的內(nèi)核也支持,采用串口和模組通信。使用時添加文件到工程中,頭文件引用即可。此外,需要外部實現(xiàn)模組的復位操作,一般是對管腳拉高一段時間,復位函數(shù)需要指定函數(shù)為。四實例以下為使用的庫,實現(xiàn)對接自建。 一、說明 本lib庫基于STM32F407編譯,其他的cortexM4內(nèi)...
摘要:文章目錄一原理二實現(xiàn)顯示中文滾動顯示顯示字符串讀取溫濕度顯示溫濕度三結果開機顯示歡迎信息循環(huán)讀取溫濕度以及滾動顯示我的四總結五參考六源碼一原理的定義就是串行外圍設備接口。 ...
閱讀 2461·2021-10-09 09:41
閱讀 3337·2021-09-26 09:46
閱讀 906·2021-09-03 10:34
閱讀 3244·2021-08-11 11:22
閱讀 3435·2019-08-30 14:12
閱讀 779·2019-08-26 11:34
閱讀 3400·2019-08-26 11:00
閱讀 1841·2019-08-26 10:26