#ifndef __RS485_H
#define __RS485_H
#include "sys.h"
#include "stdio.h"
#define SLAVE_ADDR 0x01
#define RX_BUF_SIZE 64
#define RS485_TX_EN() GPIO_SetBits(GPIOB, GPIO_Pin_7)
#define RS485_RX_EN() GPIO_ResetBits(GPIOB, GPIO_Pin_7)
void UART5_RS485_Init(uint32_t baud);
void RS485_Send(uint8_t *buf, uint16_t len);
void Modbus_Slave_Poll(void);
extern uint16_t Modbus_CRC16(uint8_t *buf, uint16_t len);
extern volatile uint8_t rx_buf[RX_BUF_SIZE];
extern volatile uint8_t rx_len ;
extern uint16_t HoldingReg[10];
#endif
#include "RS485.h"
#include "sys.h"
uint16_t Modbus_CRC16(uint8_t *buf, uint16_t len);
volatile uint8_t rx_buf[RX_BUF_SIZE];
volatile uint8_t rx_len = 0;
uint16_t HoldingReg[10] = {
3300, // 40001:电压 mV
123, // 40002:示例数据
};
void UART5_IRQHandler(void)
{
if(USART_GetITStatus(UART5, USART_IT_RXNE))
{
if(rx_len < RX_BUF_SIZE)
rx_buf[rx_len++] = USART_ReceiveData(UART5);
}
}
void UART5_RS485_Init(uint32_t baud)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(
RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC |
RCC_APB2Periph_GPIOD |
RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
/* TX PC12 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* RX PD2 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* DE PB7 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RS485_RX_EN();
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(UART5, &USART_InitStructure);
USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);
USART_Cmd(UART5, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void RS485_Send(uint8_t *buf, uint16_t len)
{
RS485_TX_EN();
for(uint16_t i = 0; i < len; i++)
{
USART_SendData(UART5, buf[i]);
while(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
}
while(USART_GetFlagStatus(UART5, USART_FLAG_TC) == RESET);
RS485_RX_EN();
}
uint16_t Modbus_CRC16(uint8_t *buf, uint16_t len)
{
uint16_t crc = 0xFFFF;
for(uint16_t i = 0; i < len; i++)
{
crc ^= buf[i];
for(uint8_t j = 0; j < 8; j++)
{
if(crc & 1) crc = (crc >> 1) ^ 0xA001;
else crc >>= 1;
}
}
return crc;
}
void Modbus_Slave_Poll(void)
{
if(rx_len < 8) return;
uint16_t crc_calc = Modbus_CRC16((uint8_t*)rx_buf, rx_len-2);
uint16_t crc_recv = rx_buf[rx_len-2] | (rx_buf[rx_len-1]<<8);
if(crc_calc != crc_recv) goto clear;
if(rx_buf[0] != SLAVE_ADDR) goto clear;
if(rx_buf[1] == 0x03)
{
uint16_t start = (rx_buf[2]<<8) | rx_buf[3];
uint16_t num = (rx_buf[4]<<8) | rx_buf[5];
uint8_t tx[64], idx = 0;
tx[idx++] = SLAVE_ADDR;
tx[idx++] = 0x03;
tx[idx++] = num * 2;
for(uint16_t i=0;i<num;i++)
{
tx[idx++] = HoldingReg[start+i] >> 8;
tx[idx++] = HoldingReg[start+i] & 0xFF;
}
uint16_t crc = Modbus_CRC16(tx, idx);
tx[idx++] = crc & 0xFF;
tx[idx++] = crc >> 8;
RS485_Send(tx, idx);
}
clear:
rx_len = 0;
}