欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2219|回復: 7
收起左側

采用RS485來進行數據通訊,串口采用的是DMA+空閑中斷來接收數據,但始終無法進入中斷

[復制鏈接]
ID:1081116 發表于 2023-5-31 15:25 | 顯示全部樓層 |閱讀模式
1.采用485來進行數據通訊,串口采用的是DMA+空閑中斷來接收數據,但始終無法進入中斷!

2.采用串口通訊助手,發送數據可以正常接收到返回幀,證明器件沒有問題
51hei.png

rs485.h
    #ifndef __RS485_H_
    #define __RS485_H_
    #include "./SYSTEM/sys/sys.h"
    #include "./BSP/PCF8574/pcf8574.h"
    #include "./BSP/LED/led.h"
    #define DMA_REC_LEN 50
    /*IO申明*/
    #define USART_TX_PIN        GPIO_PIN_2
    #define USART_TX_PORT        GPIOA
    #define USART_RX_PIN        GPIO_PIN_3
    #define USART_RX_PORT        GPIOA
    /*IO引腳定義*/
    #define RS485_RE_IO 6
    /* 函數申明 */
    void MY_RS485_Init(uint32_t bound);
    void MY_RS485_DMA_Init(void);
    void RS485_Mode(uint8_t mode);
    void RS485_Send_Data(uint8_t *data,uint8_t len);
    void HAL_UART_ReceiveIdle(UART_HandleTypeDef *huart);
    void Copy_Data(uint8_t *buf,uint16_t len);
    #endif
4.rs485.c
    #include "./BSP/RS485/rs485.h"
    /* 采用的堵塞發送  DMA+空閑中斷接收的模式來進行數據的收發 */
    #define UART2_DMA_RX            1                //1使能    0失能  使用DMA接收的原理
    #define UART2_DMA_TX            0                //1使能    0失能  使用DMA傳輸的原理   未寫入
    #define CHECK_NONE_ONE_STOP        1                //1個停止位  1使能    0失能
    #define CHECK_NONE_TWO_STOP       0                //2個停止位
    #define CHECK_EVEN                0                //偶校驗
    #define CHECK_ODD                0                //奇校驗
    UART_HandleTypeDef USART2_RS485Handler;            //串口2的句柄
    DMA_HandleTypeDef  USART2_DMAHandler;            //DMA句柄
    uint8_t DMA_REC_BUF[DMA_REC_LEN]={0};            //最大不能超過50個字節  DMA接收緩存區
    uint16_t RX_CNT = 0;                            //計數值
    uint8_t rx_end_flag = 0;                        //接收完成標志位
    uint8_t Data_BackUp[DMA_REC_LEN]={0};            //數據備份接收緩存區
    uint16_t datalen_backup = 0;                    //當前數據接收緩存區中的數據量
    /*串口2空閑傳輸+DMA數據傳輸*/
    void MY_RS485_Init(uint32_t bound){
        /*申明IO口相關參數*/
        GPIO_InitTypeDef GPIO_InitStruct;
        __HAL_RCC_USART2_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();  
    //    GPIO_InitStruct.Pin = USART_TX_PIN|USART_RX_PIN;               /* TX RX引腳 */
        GPIO_InitStruct.Pin = USART_TX_PIN;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;                          /* 復用推挽輸出 */
    //    GPIO_InitStruct.Pull = GPIO_PULLUP;                          /* 上拉 */
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;                     /* 高速 */
        GPIO_InitStruct.Alternate = GPIO_AF7_USART2;                     /* 復用為USART2 */
        HAL_GPIO_Init(USART_TX_PORT, &GPIO_InitStruct);                  /* 初始化發送引腳 */
        GPIO_InitStruct.Pin  = USART_RX_PIN;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(USART_RX_PORT, &GPIO_InitStruct);
        /*配置RS485相關參數*/
        USART2_RS485Handler.Instance = USART2;
        USART2_RS485Handler.Init.BaudRate=bound;
        USART2_RS485Handler.Init.HwFlowCtl =UART_HWCONTROL_NONE;
        USART2_RS485Handler.Init.Mode =UART_MODE_TX_RX;
        USART2_RS485Handler.Init.Parity =UART_PARITY_NONE;
        USART2_RS485Handler.Init.WordLength =UART_WORDLENGTH_8B;
    #if(CHECK_NONE_ONE_STOP== 1)
        USART2_RS485Handler.Init.StopBits =UART_STOPBITS_1;
    #endif
    #if(CHECK_NONE_TWO_STOP== 1)
        USART2_RS485Handler.Init.StopBits =UART_STOPBITS_2;
    #endif
    #if(CHECK_EVEN== 1)
        USART2_RS485Handler.Init.Parity =UART_PARITY_EVEN;
    #endif
    #if(CHECK_ODD== 1)
        USART2_RS485Handler.Init.Parity =UART_PARITY_ODD;
    #endif
        HAL_UART_Init(&USART2_RS485Handler);
    //    __HAL_UART_ENABLE_IT(&USART2_RS485Handler,UART_IT_RXNE);
        USART2_RS485Handler.Instance->CR1 |= USART_CR1_RXNEIE;
        RS485_Mode(0);
    #if(UART2_DMA_RX== 1)
        /*連接DMA和USART_RX接受使能*/
    //    __HAL_UART_ENABLE_IT(&USART2_RS485Handler,UART_IT_IDLE);                //使能串口的空閑中斷
        USART2_RS485Handler.Instance->CR1 |= USART_CR1_IDLEIE;
        HAL_UART_Receive_DMA(&USART2_RS485Handler, DMA_REC_BUF, DMA_REC_LEN);    //使能DMA接收,將數據存儲在DMA_REC_BUF數據緩存區中    DMA_REC_LEN是定義的DMA的最大傳輸數量
    #endif
        /*開啟接受中斷&配置優先級*/
        HAL_NVIC_SetPriority(USART2_IRQn, 2, 1);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
    }
    void MY_RS485_DMA_Init(void){
        /* 配置DMA接受句柄 */
        __HAL_RCC_DMA1_CLK_ENABLE();
        USART2_DMAHandler.Instance =DMA1_Stream5;
        USART2_DMAHandler.Init.Channel =DMA_CHANNEL_4;
        USART2_DMAHandler.Init.Direction =DMA_PERIPH_TO_MEMORY;
        USART2_DMAHandler.Init.PeriphInc =DMA_PINC_DISABLE;
        USART2_DMAHandler.Init.MemInc =DMA_MINC_ENABLE;
        USART2_DMAHandler.Init.PeriphDataAlignment =DMA_PDATAALIGN_BYTE;
        USART2_DMAHandler.Init.MemDataAlignment =DMA_MDATAALIGN_BYTE;
        USART2_DMAHandler.Init.Mode =DMA_CIRCULAR;
        USART2_DMAHandler.Init.Priority =DMA_PRIORITY_MEDIUM;
        USART2_DMAHandler.Init.FIFOMode =DMA_FIFOMODE_DISABLE;
        HAL_DMA_Init(&USART2_DMAHandler);
        __HAL_LINKDMA(&USART2_RS485Handler,hdmarx,USART2_DMAHandler);        //將USART2句柄與DMA句柄連接起來
        __HAL_DMA_ENABLE(&USART2_DMAHandler);
        /*  配置優先級 */
        HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
    }
    void  DMA1_Stream5_IRQHandler(void){
        HAL_DMA_IRQHandler(&USART2_DMAHandler);
    }
    void USART2_IRQHandler(void){
        LED1_TOGGLE();
        HAL_UART_IRQHandler(&USART2_RS485Handler);
        HAL_UART_ReceiveIdle(&USART2_RS485Handler);
        while(HAL_UART_Receive_DMA(&USART2_RS485Handler, DMA_REC_BUF, DMA_REC_LEN) != HAL_OK);
    }
    void HAL_UART_ReceiveIdle(UART_HandleTypeDef *huart){
    //    uint8_t res = 0;
    //    LED1_TOGGLE();
        if(huart->Instance == USART2){
    #if(UART2_DMA_RX== 1)
            if((__HAL_UART_GET_FLAG(&USART2_RS485Handler, UART_FLAG_IDLE)) != RESET){    //接受到了一幀數據
                __HAL_DMA_DISABLE(&USART2_DMAHandler);                                    //失能DMA傳輸
                RX_CNT = DMA_REC_LEN - __HAL_DMA_GET_COUNTER(&USART2_DMAHandler);        //定義的最大傳輸數量-通道中剩余的數量=接收到數量
                Copy_Data(DMA_REC_BUF,RX_CNT);
                __HAL_UART_CLEAR_FLAG(&USART2_RS485Handler, UART_FLAG_IDLE);            //清除相關標記位
                __HAL_DMA_ENABLE(&USART2_DMAHandler);                                    //使能DMA傳輸
                rx_end_flag = 1;
            }
    #endif
        }
    }
    //void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
    //    uint8_t res = 0, i;
    //   
    ////    LED1_TOGGLE();
    //    if(huart->Instance == USART2){
    //#if(UART2_DMA_RX== 0)
    //        if((__HAL_UART_GET_FLAG(&USART2_RS485Handler, UART_FLAG_IDLE)) != RESET){    //接受到了一幀數據
    //            __HAL_DMA_DISABLE(&USART2_DMAHandler);                                    //失能DMA傳輸
    //            RX_CNT = DMA_REC_LEN - __HAL_DMA_GET_COUNTER(&USART2_DMAHandler);        //定義的最大傳輸數量-通道中剩余的數量=接收到數量
    //            Copy_Data(DMA_REC_BUF,RX_CNT);
    //            __HAL_UART_CLEAR_FLAG(&USART2_RS485Handler, UART_FLAG_IDLE);            //清除相關標記位
    //            __HAL_DMA_ENABLE(&USART2_DMAHandler);                                    //使能DMA傳輸
    //            rx_end_flag = 1;
    //        }
    //#endif
    //    }
    //}
    //備份接收到的數據
    void Copy_Data(uint8_t *buf,uint16_t len){
        uint16_t i;
        datalen_backup = len;
        for(i = 0; i < len; i++){
            Data_BackUp = buf;
        }
    }
    void RS485_Send_Data(uint8_t *data,uint8_t len){
        RS485_Mode(1);
        while(__HAL_UART_GET_FLAG(&USART2_RS485Handler,UART_FLAG_TC) == RESET);            //等待傳輸完成
        HAL_UART_Transmit(&USART2_RS485Handler,data, len, 1000);                        //再次發送數據
        while(__HAL_UART_GET_FLAG(&USART2_RS485Handler,UART_FLAG_TC) == RESET);            //等待數據傳輸完成
        RX_CNT = 0;
        RS485_Mode(0);
    }
    /* 選擇RS485的模式  1--w  0--r */
    void RS485_Mode(uint8_t mode){
        PCF8574_Write_Bit(RS485_RE_IO, mode);
    }
5.采用MODBUS來進行檢測溫度
    #ifndef __RS_WS_N018_H_
    #define __RS_WS_N018_H_
    #include "./SYSTEM/sys/sys.h"
    #include "./SYSTEM/delay/delay.h"
    #include "./SYSTEM/usart/usart.h"
    #include "./BSP/RS485/rs485.h"
    #include "string.h"
    /*設備地址*/
    #define DEV_ADDR 0x01
    /*功能碼*/
    #define FUN_CODE 0x03
    /*寄存器地址*/
    #define HUMI_ADDR  0x0000
    #define TEMP_ADDR  0x0001
    /*函數申明*/
    uint16_t CRC_16_HEX(uint8_t *Buf, uint8_t CRC_CNT);
    void N018_Send_HTCommand(void);
    uint8_t N018_Scan(float *temp,float *humi);
    #endif
6.
    #include "./BSP/RS_WS_N018/rs_ws_n018.h"
    //extern
    extern uint8_t Data_BackUp[DMA_REC_LEN];
    extern uint8_t rx_end_flag;
    uint8_t RS485_Send_Buf[10] = {0};
    uint8_t CRC_BUF[2] ={0};
    //CRC16校驗算法 適用于16進制處理
    uint16_t CRC_16_HEX(uint8_t *Buf, uint8_t CRC_CNT)
    {
        unsigned long CRC_Temp;
        unsigned char i,j;
        CRC_Temp = 0xffff;
        for (i=0; i<CRC_CNT; i++) {
    //        printf("%x\r\n",Buf);
            CRC_Temp ^= Buf;
            for (j=0; j<8; j++) {
                if (CRC_Temp & 0x01)
                    CRC_Temp = (CRC_Temp >>1 ) ^ 0xA001;
                else
                    CRC_Temp = CRC_Temp >> 1;
            }
        }
        return(CRC_Temp>>8|CRC_Temp<<8);  
    }
    /**
    *@brief send command of reading humidity and temperature
    */
    void N018_Send_HTCommand(void){
        uint8_t addr_buf[2] ={DEV_ADDR,FUN_CODE};
        /*發送讀取溫濕度指令*/
        RS485_Send_Buf[0] = addr_buf[0];
        RS485_Send_Buf[1] = addr_buf[1];
        RS485_Send_Buf[2] = (uint8_t)HUMI_ADDR>>8;                //發送濕度首地址
        RS485_Send_Buf[3] = (uint8_t)HUMI_ADDR&0xFF;
        RS485_Send_Buf[4] = 0x00;                                //發送兩個字節長度,包括了溫度和濕度
        RS485_Send_Buf[5] = 0x02;
        CRC_BUF[0] = (CRC_16_HEX(RS485_Send_Buf, 6)>>8);
        CRC_BUF[1] = CRC_16_HEX(RS485_Send_Buf, 6)&0xFF;
        RS485_Send_Buf[6] = CRC_BUF[0];
        RS485_Send_Buf[7] = CRC_BUF[1];
        RS485_Send_Data(RS485_Send_Buf,8);
    }
    uint8_t N018_Scan(float *temp,float *humi){
        uint8_t ret = 1;
        uint16_t temperature = 0, humidity = 0;
        /* 發送讀取溫濕度指令 */
    //    N018_Send_HTCommand();
        RS485_Send_Buf[0] = 0X01;
        RS485_Send_Buf[1] = 0X03;
        RS485_Send_Buf[2] = 0X00;                //發送濕度首地址
        RS485_Send_Buf[3] = 0X00;
        RS485_Send_Buf[4] = 0x00;                                //發送兩個字節長度,包括了溫度和濕度
        RS485_Send_Buf[5] = 0x02;
        RS485_Send_Buf[6] = 0XC4;
        RS485_Send_Buf[7] = 0X0B;
        RS485_Send_Data(RS485_Send_Buf,8);
        printf("send successfully\r\n");
         while(rx_end_flag == 0);                                            //接受到了濕度數據
        printf("receive successfully\r\n");
        if(Data_BackUp[0]==RS485_Send_Buf[0]&&Data_BackUp[1]==RS485_Send_Buf[1]){        //判斷命令和地址是否一致
            CRC_BUF[0] = (CRC_16_HEX(Data_BackUp, 7)>>8);
            CRC_BUF[1] = CRC_16_HEX(Data_BackUp, 7)&0xFF;
            if(CRC_BUF[0]==Data_BackUp[7]&&CRC_BUF[1]==Data_BackUp[8]){                //判斷校驗碼是否正確
                humidity = Data_BackUp[3]<<8|Data_BackUp[4];
                printf("humi:%d\r\n",humidity);//測試代碼
                *humi = humidity % 10;
                if(Data_BackUp[5]&0x80)            //溫度為負
                    temperature = ~(Data_BackUp[5]<<8|Data_BackUp[6])+1;
                else                        //溫度為正
                    temperature = Data_BackUp[5]<<8|Data_BackUp[6];
                *temp = temperature % 10;
                ret = 0;
            }
        }
        printf("receive successfully\r\n");
        return ret;
    }

回復

使用道具 舉報

ID:883242 發表于 2023-5-31 20:52 | 顯示全部樓層
數據幀長度不固定沒法用DMA來接收。
回復

使用道具 舉報

ID:1081213 發表于 2023-5-31 21:08 | 顯示全部樓層
數據幀長度不固定沒法用DMA來接收。
回復

使用道具 舉報

ID:1081116 發表于 2023-6-1 08:16 | 顯示全部樓層
Hephaestus 發表于 2023-5-31 20:52
數據幀長度不固定沒法用DMA來接收。

雖然數據幀長度不固定 但是設置了DMA最大接收長度呀
回復

使用道具 舉報

ID:68189 發表于 2023-6-1 08:29 | 顯示全部樓層
沈小小小仙女 發表于 2023-6-1 08:16
雖然數據幀長度不固定 但是設置了DMA最大接收長度呀

達不到設置的DMA數據長度,不會觸發DMA中斷。我是這么理解的。
回復

使用道具 舉報

ID:1081116 發表于 2023-6-1 08:44 | 顯示全部樓層
a1231233132 發表于 2023-5-31 21:08
數據幀長度不固定沒法用DMA來接收。

DMA+空閑中斷可以完成接收不定長的數據呀
回復

使用道具 舉報

ID:744809 發表于 2023-6-1 10:59 | 顯示全部樓層
應該是dma配置有問題,可以用stm32cubemx生成配置代碼,更簡單一些
回復

使用道具 舉報

ID:1081116 發表于 2023-6-3 15:01 | 顯示全部樓層
wpppmlah 發表于 2023-6-1 08:29
達不到設置的DMA數據長度,不會觸發DMA中斷。我是這么理解的。

好的 謝謝
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表