單片機
返回首頁

STM32 485通信 自我學習總結 控制380V變頻器去控制380V電機

2021-08-25 來源:eefocus

        準備總結一下學習過程中的485通信知識!----------------------------------------------------


        先描述一下學習STM32與485通信的時候想實現的功能--------


        首先是完成雙機通信中的雙向通信----這里定義A為主機發送指令給從機B,從機B在接收到主機A的指令后,判斷有效位的正確性,如果正確將這個指令通過RS232串口顯示到串口助手里,觀察整個指令是否接收正確-----同時在從機B接收到主機A指令后,向主機A發送指定數據----主機A在接收到從機B數據后判斷有效位的正確性,如果正確則通過RS232打印到串口助手,然后觀察完整數據。--------這里的判斷比較簡單------只是判斷接收數據的最后一位是否是規定的字符----為了數據的準確性,可以增加判斷方法。


        


        第一步是配置RS232的串口,這里使用USART1,測試printf函數的輸出是否正常----------這里就不敘述了!


注意在主機的USART1中要打開接收中斷-- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//打開接收終端


        第二步是配置RS485,這里使用USART2,配置如下---------


void USART2_Config(void)

{

        GPIO_InitTypeDef GPIO_InitStructure;

        USART_InitTypeDef USART_InitStructure;

  

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA, &GPIO_InitStructure);

       


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

        GPIO_Init(GPIOA, &GPIO_InitStructure);

      


        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;

         //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOB, &GPIO_InitStructure);

 

        USART_InitStructure.USART_BaudRate = 115200;

        USART_InitStructure.USART_WordLength = USART_WordLength_8b;

        USART_InitStructure.USART_StopBits = USART_StopBits_1;

        USART_InitStructure.USART_Parity = USART_Parity_No ;

        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;



        USART_Init(USART2, &USART_InitStructure); 

        USART_Cmd(USART2, ENABLE);

  

        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//打開接收終端

        USART_ClearFlag(USART2, USART_FLAG_TC);

}


void MyPrintfByte(unsigned char byte)//發送一個字節

{

        USART_SendData(USART2, byte);  

        while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);       

}

void MyPrintfStr(unsigned char *s)//發送字符串

{

        uint8_t i=0;


        while(s[i]!='')

        {

                USART_SendData(USART2,s[i]); 

                while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);  

                i++;   

        }

}

void MyPrintfArray(uint8_t send_array[],uint8_t num)//發送數組中指定個數

{

        uint8_t i=0;


        while(i        {               

                USART_SendData(USART2,send_array[i]); 

                while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);  

                i++;     

        }        

}


        第三部是在中斷里寫接收函數--------------


void USART1_IRQHandler(void)//232接收中斷函數---主要是在主機中

{        

        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到數據

        {        

                USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清標志位

                RS232_RX_BUF[RS232_RX_CNT++]=USART_ReceiveData(USART1);

                if( RS232_RX_CNT==4)

                        RS232_RX_CNT=0;    

        }


void USART2_IRQHandler(void)  //485中斷接收函數

{       

        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到數據

        {        

                USART_ClearITPendingBit(USART2, USART_IT_RXNE);//清標志位

                RS485_RX_BUF[RS485_RX_CNT++]=USART_ReceiveData(USART2); //將接收到的數據保存到指定數組

                if( RS485_RX_CNT==9)//接收指定長度為9個數據

                        RS485_RX_CNT=0;     

        }


        第四步是對中斷的優先級進行配置----


static void NVIC_Configuration(void)

{

      NVIC_InitTypeDef NVIC_InitStructure;

  

      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  

      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = ENABLE;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

  

      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  

      NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = ENABLE;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

}


        第五部是主函數----------


---------------------------主機----------------------------------


int main(void)

{

        uint8_t i,flag=0;

  


        USART2_Config(); 

        USART1_Config(); 

        GPIO_Config();

        NVIC_Configuration();


        printf("485主機rn");


        while(1)

        {

                GPIO_SetBits(GPIOB,GPIO_Pin_5);//發送模式

                Delay(50000);  //必要的延時

                if(RS232_RX_BUF[3]=='1')      //通過串口助手發送一組數據,根據不同數據下面向從機發送不同的指令

                        MyPrintfStr("12345678!");

                else if(RS232_RX_BUF[3]=='2')

                        MyPrintfStr("abcdefgh@");

                else if(RS232_RX_BUF[3]=='3')

                       MyPrintfStr("ABCDEFGH#");


                RS485_RX_BUF[8]='-';  //將接收數據的最后一位設置為其它

                Delay(50000);

                GPIO_ResetBits(GPIOB,GPIO_Pin_5);//接收模式

                Delay(50000);

                //USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

                flag=0;

                while(!(RS485_RX_BUF[8]=='T')&&flag<20)//等待接收到數據,并且最后一位數據位---T---或者超時退出循環---超時數值比較重要,太小會使數據丟失。

                {

                       Delay(0x666ee);

                      flag++;

                }

                for(i=0;i<9;i++)  //打印出接收到從機的數據

                {

                       if(i<8)

                            printf("%c",RS485_RX_BUF[i]); 

                       else

                            printf("%crn",RS485_RX_BUF[i]); 

                } 

                Delay(0x6666ee);

        }

}


------------------------------------------從機--------------------------------------


int main(void)

{

        uint8_t i;

     


        USART2_Config();

        GPIO_Config();


        USART1_Config();

        NVIC_Configuration();

  

        printf("rn485從機rn");


        while(1) 

        {

                RS485_RX_BUF[8]='+';

                Delay(50000);

                GPIO_ResetBits(GPIOB,GPIO_Pin_5); //接收模式

                Delay(50000);

                while(!(RS485_RX_BUF[8]=='!')&&!(RS485_RX_BUF[8]=='@')&&!(RS485_RX_BUF[8]=='#'));//簡單判斷最后一位


                for(i=0;i<9;i++)//打印出接收到的數據

                {

                        if(i<8)

                            printf("%c",RS485_RX_BUF[i]); 

                        else

                            printf("%crn",RS485_RX_BUF[i]); 

                }

                Delay(0x6666ee);


                GPIO_SetBits(GPIOB,GPIO_Pin_5); //發送模式

                Delay(50000);

                if(RS485_RX_BUF[8]=='!')  //根據主機發送的不同指令返回發送不同數據給主機

                        MyPrintfStr("ascii789T");

                else if(RS485_RX_BUF[8]=='@')

                        MyPrintfStr("ASCII123T");

                else if(RS485_RX_BUF[8]=='#')

                        MyPrintfStr("CHINA456T");

        }

}


第六步是下載測試--------------------------------


01---復位兩個開發板----------------

02----通過串口助手向主機發送指令1111------指令要求---必須4位----只判斷最后一位是否為1或者2或者3------0001與1111表示一樣的指令-----3312與8762表示一樣。------------發現從機接收到了主機發送的指令12345678!------主機也接收到了從機返回的數據ascii789T。

03----通過串口助手向主機發送指令2222------指令要求---必須4位----只判斷最后一位是否為1或者2或者3------0001與1111表示一樣的指令-----3312與8762表示一樣。------------發現從機接收到了主機發送的指令abcdefgh@------主機也接收到了從機返回的數據ASCII123T。

04----通過串口助手向主機發送指令3333------指令要求---必須4位----只判斷最后一位是否為1或者2或者3------0001與1111表示一樣的指令-----3312與8762表示一樣。------------發現從機接收到了主機發送的指令ABCDEFGH#------主機也接收到了從機返回的數據CHINA456T。

-------------------目前是9個數據的收發----是正常的----------接下來將測試收發更多數據-----不知道效果如何-----------------


14-10-30


----------------------------------17個數據也是正常的-------------再多一些也是可以的----------

----------------------------在調試過程中有一些問題出現---------------------


1.---其中有一個是-----------主機接收時總是出錯,想了很多辦法,也仔細看了程序,最后發現從機接收正常,于是將主機與從機交換,發現主機正常了,而從機出錯了,得出結論是硬件的問題,后來仔細觀察發現焊接不是很好,雖然都是焊接上了的,最后重新加錫牢固焊接-----通信完全正常了!


2.---第二個就是線的長度問題----我試驗的時候使用的是20cm的線,通訊完全正常。后來我直接上500米的線,發現暫時沒有反應,現在我用3-4M的網線,通訊正常,后面再慢慢加長--------------聽說要加上拉電阻---不知道對不對---打算試一試!


3.---線長有十幾米,也沒有加上拉電阻,通信時完全正常的,上面的程序需要在接收過程中實現一個糾錯的簡單功能,防止在長時間通信過程中偶爾丟失數據,從而影響后面的數據接收-------


------主機main------

-------從機main--------

4.---趕快焊接第三個板子------做多機通信實驗---看效果!


14-11-1


5.---今天焊接了兩個板子,加起來有四個,現在在多機通信,過程中有幾個問題出現,-------上面雙機通信時主機是不停發送指令的,但是在多機通信的時候不可用,會出現錯誤-----我簡單理解是要釋放總線-----這個度不好把握-----把握好可以增加通信頻率---次數


6.---我現在是主機接收串口指令,發送指令給從機,3個從機根據指令地址判斷,是否需要返回數據----恢復通信是沒有問題的------就是反應慢點,串口給主機指令后,3秒鐘才接收到從機返回的數據----------不過一步一步來,再調試一下!


---------------------圖片---------------------


------------指令1111---------

------------指令2222---------

------------指令3333--------

7.---慢慢調試了延時,現在的反應快多了,一秒不到--------------!


14-11-2


8.---前幾天在學習STM32的485通信,基本搞清楚了原理,也實際操作成功---后續還將進一步學習---與變頻器通信,從而去控制380V電機!


---------------------實物圖------------------

------14-11-7--------------------通過PC串口發送指令給主機,主機再向變頻器發送指令,去控制380V電機的速度,啟停,正反轉!-----------------見下圖----------------






進入單片機查看更多內容>>
相關視頻
  • TI 新一代 C2000? 微控制器:全方位助力伺服及馬達驅動應用

  • MSP430電容觸摸技術 - 防水Demo演示

  • 直播回放: Microchip Timberwolf? 音頻處理器在線研討會

  • 新唐 8051單片機教程

  • 基于靈動MM32W0系列MCU的指夾血氧儀控制及OTA升級應用方案分享

  • 基于靈動MM32SPIN系列MCU的無感FOC便攜冰箱應用方案分享

    相關電子頭條文章
萝卜大香蕉