基於STM32 的485通訊實驗(f103)


1.前言-單片機的通訊

在單片機通訊方式多種多樣的今天,基本可以划分為兩類,即同步和異步通信。單片機要正常交流(即交換數據和讀寫命令)離不開通訊,單片機之間或者單片機與及外設之間的通訊都離不開這兩類通訊。

通訊方式的分類

 

同步和異步通信怎么區別?

帶時鍾同步信號傳輸的是同步傳輸,不帶時鍾同步信號的是異步傳輸(此時要求通訊雙方同波特率)。

下面我將通過基於stm32f103芯片以及MDK5軟件進行開發485通訊實驗(其實485通訊就是利用uart串口實現的),需要准備:

一台裝着MDK5軟件的電腦

ST-LInk燒錄器,STM32正點原子精英開發板2套(包含TFTLCD顯示屏)

兩根杜邦線

 

 

 

2.485通訊簡介

         要開展485通訊實驗之前,485得對自己進行一次自我介紹。485通訊本質上是通過串口經過485芯片改變電壓與及阻抗,內在的信息沒有改變,之后通過電壓電流等信號傳給另一個單片機的485芯片,該芯片接至該單片進的串口。

485(一般稱作RS485/EIA-485)是隸屬於OSI模型物理層的電氣特性規定為2線,半雙工,多點通信的標准。它的電氣特性和RS-232大不一樣。用纜線兩端的電壓差值來表示傳遞信號。RS485僅僅規定了接受端和發送端的電氣特性。它沒有規定或推薦任何數據協議。

RS485的特點包括:

1) 接口電平低,不易損壞芯片。RS485的電氣特性:邏輯“1”以兩線間的電壓差為+(2~6)V表示;邏輯“0”以兩線間的電壓差為-(2~6)V表示。接口信號電平比RS232降低了,不易損壞接口電路的芯片,且該電平與TTL電平兼容,可方便與TTL 電路連接。

2) 傳輸速率高。10米時,RS485的數據最高傳輸速率可達35Mbps,在1200m時,傳輸速度可達100Kbps。

3) 抗干擾能力強。RS485接口是采用平衡驅動器和差分接收器的組合,抗共模干擾能力增強,即抗噪聲干擾性好。

4) 傳輸距離遠,支持節點多。RS485總線最長可以傳輸1200m以上(速率≤100Kbps)

一般最大支持32個節點,如果使用特制的485芯片,可以達到128個或者256個節點,最大的可以支持到400個節點。

RS485推薦使用在點對點網絡中,線型,總線型,不能是星型,環型網絡。理想情況下RS485需要2個匹配電阻,其阻值要求等於傳輸電纜的特性阻抗(一般為120Ω)。沒有特性阻抗的話,當所有的設備都靜止或者沒有能量的時候就會產生噪聲,而且線移需要雙端的電壓差。沒有終接電阻的話,會使得較快速的發送端產生多個數據信號的邊緣,導致數據傳輸出錯。485推薦的連接方式如圖29.1.1所示:

 

 

在上面的連接中,如果需要添加匹配電阻,我們一般在總線的起止端加入,也就是主機和設備4上面各加一個120Ω的匹配電阻。

由於RS485具有傳輸距離遠、傳輸速度快、支持節點多和抗干擾能力更強等特點,所以RS485有很廣泛的應用。

精英STM32開發板采用SP3485作為收發器,該芯片支持3.3V供電,最大傳輸速度可達10Mbps,支持多達32個節點,並且有輸出短路保護。該芯片的框圖如圖29.1.2所示:

 

 

 

圖中A、B總線接口,用於連接485總線。RO是接收輸出端,DI是發送數據收入端,RE是接收使能信號(低電平有效),DE是發送使能信號(高電平有效)。

本章,我們通過該芯片連接STM32的串口2,實現兩個開發板之間的485通信。本章將實

 

現這樣的功能:通過連接兩個精英STM32開發板的RS485接口,然后由KEY0控制發送,當按下一個開發板的KEY0的時候,就發送5個數據給另外一個開發板,並在兩個開發板上分別顯示發送的值和接收到的值。

本章,我們只需要配置好串口2,就可以實現正常的485通信了,串口2的配置和串口1基本類似,只是串口的時鍾來自APB1,最大頻率為36Mhz。

 

 

3.軟件代碼的實現

 

在此,我將對幾個重要的函數展開詳細說明,我覺得外設模塊化進行開發跟函數模塊化開發一樣重要,一個函數最多只放幾十行代碼,同時前面要有函數說明。這樣,你寫的代碼會方便以后的修改,同時也可以讓別人快速知道你這個軟件實現的是什么功能。

void RS485_Init(u32 bound) ;

void RS485_Receive_Data(u8 *ReceiveBuf,u8 *len);

void RS485_Send_Data(u8 *SendBuf ,u8 len);

 

    void RS485_Init(u32 bound)

{

    GPIO_InitTypeDef GPIO_InitType;

    USART_InitTypeDef USART_InitType;

    NVIC_InitTypeDef NVIC_InitType;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD,ENABLE);       //使能GPIOA和GPIOD的時鍾

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);                       //使能USART2的時鍾

 

   

    GPIO_InitType.GPIO_Pin=GPIO_Pin_7;                                   //接收或者發送模式控制引腳PD7(初始化之后才能用)

    GPIO_InitType.GPIO_Mode = GPIO_Mode_Out_PP;                       //推挽輸出

    GPIO_InitType.GPIO_Speed=GPIO_Speed_50MHz;                     //這個引腳是485芯片中的發送接收控制引腳

    GPIO_Init(GPIOD,&GPIO_InitType);                                   //當PDout(7)輸出的是高電平‘1’時是發送,為‘0’時是接收

   

    GPIO_InitType.GPIO_Pin=GPIO_Pin_2;                                  //USART2的TX引腳是PA2

    GPIO_InitType.GPIO_Mode=GPIO_Mode_AF_PP;

    GPIO_InitType.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(GPIOA,&GPIO_InitType);

   

    GPIO_InitType.GPIO_Pin=GPIO_Pin_3;                                  //USART2的RX引腳是PA3

    GPIO_InitType.GPIO_Mode=GPIO_Mode_IN_FLOATING;

    GPIO_InitType.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(GPIOA,&GPIO_InitType);

   

    #ifdef EN_RS485_RX

        USART_InitType.USART_BaudRate=bound;                                        //串口2的初始化

        USART_InitType.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

        USART_InitType.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

        USART_InitType.USART_Parity=USART_Parity_No;                       //其中重要的是USART_Mode要既能接收又能發送

        USART_InitType.USART_StopBits=USART_StopBits_1;                   //USART2的波特率都設置為9600

        USART_InitType.USART_WordLength=USART_WordLength_8b;

        USART_Init(USART2,&USART_InitType);

       

        NVIC_InitType.NVIC_IRQChannel=USART2_IRQn;                          //USART2中斷初始化

        NVIC_InitType.NVIC_IRQChannelCmd=ENABLE;                            //其實這個中斷主要是對發送的數據及時處理,使接收時便捷高效

        NVIC_InitType.NVIC_IRQChannelPreemptionPriority=3;

        NVIC_InitType.NVIC_IRQChannelSubPriority=3;

        NVIC_Init(&NVIC_InitType);

       

       

        USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);            //要用到USART2中斷除了初始化之外當然要對中斷進行配置以及使能

        USART_Cmd(USART2,ENABLE);                                 //明確發生什么時會進入串口中斷

    #endif

    RX485_TX_EN=0;              //默認接收模式   

}

 

這里的串口中斷函數,發送的數據被接收數據寄存器接收到,就會觸發中斷,進行處理

#ifdef EN_RS485_RX

 

u8 RS485_RX_BUF[64];

u8 RS485_RX_CNT=0;

void USART2_IRQHandler(void)       //發送完數據就使能接收中斷,使串口可以接收數據到緩沖區(數組RS485_RX_BUF)中

{

    u8 Res;

    if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)     

    {

       

        Res=USART_ReceiveData(USART2);

        if(RS485_RX_CNT<64)                         //一次接收的數據最多為64,超過之后將不會對發送過來的數據進行緩存

        {  

            RS485_RX_BUF[RS485_RX_CNT]=Res;

            RS485_RX_CNT++;

        }  

    }

}

 

#endif

 

 

 

 

 

void RS485_Send_Data(u8 *SendBuf ,u8 len)                       //發送處理函數

{

    u8 i;

    RX485_TX_EN=1;

    for(i=0;i<len;i++)                                                          //把長度為len的數組SendBuf發送出去

    {

        while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);        //等待發送移位數據寄存器的數據非空時(即發送結束)跳出來

        USART_SendData(USART2,SendBuf[i]);                                          //發送數據

    }

    while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);

    RX485_TX_EN=0;                                                                  //默認接收模式   

    RS485_RX_CNT=0;

}

 

 

 

void RS485_Receive_Data(u8 *ReceiveBuf,u8 *len)                     //接收處理函數

{

    u8 rxlen,i=0;

    rxlen=RS485_RX_CNT;

    delay_ms(10);

    if((rxlen==RS485_RX_CNT)&&rxlen)                             //把中斷函數處理之后的緩存數據取出來

    {

        for(i=0;i<rxlen;i++)

        {

            ReceiveBuf[i]=RS485_RX_BUF[i];                       //傳遞接收到的數據以及長度回去

        }

        *len=RS485_RX_CNT;

        RS485_RX_CNT=0;                                            //對接收的個數進行清零,方便下次接收

    }

       

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM