1.采用485来进行数据通讯,串口采用的是DMA+空闲中断来接收数据,但始终无法进入中断!
2.采用串口通讯助手,发送数据可以正常接收到返回帧,证明器件没有问题
3.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[i] = buf[i];
}
}
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[i]);
CRC_Temp ^= Buf[i];
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;
}