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