/*******************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url] cmd_usart.c
* [url=home.php?mod=space&uid=187600]@author[/url] MR.Hu
* [url=home.php?mod=space&uid=895143]@version[/url] 0.0.1
* [url=home.php?mod=space&uid=212281]@date[/url] 2021-07-18
* [url=home.php?mod=space&uid=247401]@brief[/url] 命令串口使用
*********************************************************************************************/
/*--------包含的头文件--------------------------------------------------------------------------*/
#include <string.h>
#include "cmd_usart.h"
#include "global_variables.h"
#include "CRC8_16.h"
/*--------中断声明-----------------------------------------------------------------------------*/
void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*--------全局变量-----------------------------------------------------------------------------*/
/**********************************************************************************************
* 函数名 : uart_init()
* 形参变量 :bound-------波特率
* 返回值 :无
* 函数功能 :串口1初始化
*********************************************************************************************/
void cmd_uart_init(uint32_t CMD_USART_Baudrate)
{
//-------GPIO端口设置--------------------------------------------------
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_DeInit(USART1); //复位串口1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//------USART1_TX PA.9-------------------------------------------------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化PA9
//------USART1_RX PA.10------------------------------------------------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // 初始化PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 485收发控制管脚
RCC_APB2PeriphClockCmd(RS485_RE_GPIO_CLK,ENABLE); //开启按键端口的时钟
GPIO_InitStructure.GPIO_Pin = RS485_RE_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(RS485_RE_GPIO_PORT, &GPIO_InitStructure);
GPIO_ResetBits(RS485_RE_GPIO_PORT,RS485_RE_PIN); // 控制485芯片进入接收模式
//------Usart1 NVIC 配置-------------------------------------------------------------------------------
USART_InitStructure.USART_BaudRate = CMD_USART_Baudrate; // 设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 设置字长
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 没有校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 双工模式
USART_Init(USART1, &USART_InitStructure);
// 空闲中断设置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
NVIC_Init(&NVIC_InitStructure); // 中断优先级初始化
// USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); // 接收中断使能
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); // 串口空闲中断使能
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
USART_Cmd(USART1,ENABLE);
}
/**********************************************************************************************
* 函数名 : uart_init()
* 形参变量 :bound-------波特率
* 返回值 :无
* 函数功能 :串口1初始化
*********************************************************************************************/
void device_usart_init(uint32_t DEVICE_USART_Baudrate)
{
//-------GPIO端口设置--------------------------------------------------
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_DeInit(USART2); //复位串口1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//------USART2_TX PA.2-------------------------------------------------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化PA9
//------USART1_RX PA.3------------------------------------------------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 初始化PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//------Usart1 NVIC 配置-------------------------------------------------------------------------------
USART_InitStructure.USART_BaudRate = DEVICE_USART_Baudrate; // 设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 设置字长
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 没有校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 双工模式
USART_Init(USART2, &USART_InitStructure);
// 空闲中断设置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
NVIC_Init(&NVIC_InitStructure); // 中断优先级初始化
// USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); // 接收中断使能
USART_ITConfig(USART2,USART_IT_IDLE,ENABLE); // 串口空闲中断使能
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
USART_Cmd(USART2,ENABLE);
}
/*******************************************************************************
* Function Name : DMA1_CH5_Init
* Description : Initializes Channel3 of DMA1 collection. DMA1通道5传输参数配置
* Input : None
* Return : None
*******************************************************************************/
void DMA1_CH5_USART1_RX_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能DMA1时钟
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DATAR); // 设置源数据地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) CMD_RX_Buffer; // 设置目标地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 设置传输方向:外设到存储器(此处外设为内部FLASH)
DMA_InitStructure.DMA_BufferSize = CMD_RX_Buf_Len; // 设置传输大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 指定外设地址寄存器不变。
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 指定内存地址寄存器递增。
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 设置外设数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; // 设置存储器数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 设置对应DMA工作模式为正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // DMA1通道5优先级高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 使能DMA存储器到存储器的传输方式
DMA_Init(DMA1_Channel5, &DMA_InitStructure); // 根据DMA_InitStruct中指定的参数初始化DMA1通道3
DMA_Cmd(DMA1_Channel5, ENABLE); // 使能DMA1通道5
}
/*******************************************************************************
* Function Name : DMA1_CH5_Init
* Description : Initializes Channel3 of DMA1 collection. DMA1通道5传输参数配置
* Input : None
* Return : None
*******************************************************************************/
void DMA1_CH6_USART2_RX_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能DMA1时钟
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR); // 设置源数据地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) DEVICE_RX_Buffer; // 设置目标地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 设置传输方向:外设到存储器(此处外设为内部FLASH)
DMA_InitStructure.DMA_BufferSize = CMD_RX_Buf_Len; // 设置传输大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 指定外设地址寄存器不变。
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 指定内存地址寄存器递增。
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 设置外设数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; // 设置存储器数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 设置对应DMA工作模式为正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // DMA1通道5优先级高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 使能DMA存储器到存储器的传输方式
DMA_Init(DMA1_Channel6, &DMA_InitStructure); // 根据DMA_InitStruct中指定的参数初始化DMA1通道3
DMA_Cmd(DMA1_Channel6, ENABLE); // 使能DMA1通道6
}
void DMA1_Init(void)
{
DMA1_CH5_USART1_RX_Init();
DMA1_CH6_USART2_RX_Init();
}
/**********************************************************************************************
* 函数名 :Usart1_Send()
* 形参变量 :无
* 返回值 :无
* 函数功能 :串口1发送程序
*********************************************************************************************/
void Usart1_Send(uint8_t *buf, uint16_t len)
{
uint16_t t;
RS485_TX_EN();
for(t=0;t<len;t++) // 循环发送数据
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // TXE 弹夹为空
USART_SendData(USART1,buf[t]);
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // TC,弹夹为空,枪膛也为空
RS485_RX_EN();
}
/*******************************************************************************
* 函数名 :Usart2_Send()
* 形参变量 :无
* 返回值 :无
* 函数功能 :串口2发送程序
*******************************************************************************/
void Usart2_Send(uint8_t *buf, uint16_t len)
{
uint16_t t;
for(t=0;t<len;t++) // 循环发送数据
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2,buf[t]);
}
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
}
/**********************************************************************************************
* 函数名 :USARTx_SendByte()
* 形参变量 :pUSARTx,可以是USART1、USART2、USART3
* data,要发送的字节
* 返回值 :无
*函数功能 :串口发送字符串
*********************************************************************************************/
void USARTx_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
USART_SendData(pUSARTx, data);
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
}
/**********************************************************************************************
* 函数名 :USARTx_SendStr()
* 形参变量 :pUSARTx: 可以是USART1、USART2、USART3
* *str : 字符串
* 返回值 :无
*函数功能 :串口发送字符串
*********************************************************************************************/
void USARTx_SendStr(USART_TypeDef* pUSARTx, char *str)
{
uint8_t i = 0;
RS485_TX_EN();
do
{
USARTx_SendByte(pUSARTx, *(str+i));
i++;
}while(*(str+i) != '\0');
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
RS485_RX_EN();
}
void USART2_SendStr(char *str)
{
uint8_t i = 0;
do
{
USARTx_SendByte(USART2, *(str+i));
i++;
}while(*(str+i) != '\0');
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
}
/**********************************************************************************************
* 函数名 :USART1_IRQHandler()
* 形参变量 :无
* 返回值 :无
*函数功能 :串口1中断服务程序
*********************************************************************************************/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
{
DMA_Cmd(DMA1_Channel5,DISABLE); // 关闭DMA传输
CMD_USART_Rec_Cnt = CMD_RX_Buf_Len - DMA_GetCurrDataCounter(DMA1_Channel5); // 获取串口接收的数据数量
Receive_one_fame_OK = 1; // 1帧数据完成接收
//-----------------------------------------------------------------------------------------------------------------------------------------//
// USART1->STATR; // 读状态寄存器
// USART1->DATAR; // 再读数据寄存器,此操作用于清除空闲中断标志位
DMA_SetCurrDataCounter(DMA1_Channel5,CMD_RX_Buf_Len); // 重新设置传输的数据数量
DMA_Cmd(DMA1_Channel5,ENABLE); // 开启DMA传输
USART_ReceiveData(USART1); // 读取一次数据,不然会一直进中断
USART_ClearFlag(USART1,USART_FLAG_IDLE); // 清除串口空闲中断标志位
}
}
/**********************************************************************************************
* 函数名 :USART1_IRQHandler()
* 形参变量 :无
* 返回值 :无
*函数功能 :串口1中断服务程序
*********************************************************************************************/
void USART2_IRQHandler(void)
{
uint16_t CRC_calchkval;
if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)
{
DMA_Cmd(DMA1_Channel6,DISABLE); // 关闭DMA传输
DEVICE_USART_Rec_Cnt = CMD_RX_Buf_Len - DMA_GetCurrDataCounter(DMA1_Channel6); // 获取串口接收的数据数量
DEVICE_USART_Receive_complete = 1; // 1帧数据完成接收
//--------------------------------------------------------------------------------//
CMD_TX_Buffer[0] =HEAD_FRAME_HI; // 帧头高位
CMD_TX_Buffer[1] =HEAD_FRAME_LO; // 帧头低位
CMD_TX_Buffer[2] =BOARD_ADDRESS; // 电路模块地址
CMD_TX_Buffer[3] = functional_unit; // 功能单元,同一地址的电路模块中的某个器件,00表示回复数据为版本号
CMD_TX_Buffer[4] = functional_code; // 功能码
CMD_TX_Buffer[5] =((uint8_t)((DEVICE_USART_Rec_Cnt & 0xFF00)>>8)); // 数据长度
CMD_TX_Buffer[6] =((uint8_t)( DEVICE_USART_Rec_Cnt & 0x00FF)); // 数据长度
memcpy(CMD_TX_Buffer+7,DEVICE_RX_Buffer,DEVICE_USART_Rec_Cnt); // 数据保存在第二个缓冲区
CRC_calchkval = MODBUS_CRC16(CMD_TX_Buffer, 7+DEVICE_USART_Rec_Cnt);
CMD_TX_Buffer[7+DEVICE_USART_Rec_Cnt] = ((uint8_t)(( CRC_calchkval & 0xFF00)>>8));// 校验码保存到待发送的缓存里
CMD_TX_Buffer[8+DEVICE_USART_Rec_Cnt] = ((uint8_t)( CRC_calchkval & 0x00FF) );
Usart1_Send(CMD_TX_Buffer,9+DEVICE_USART_Rec_Cnt);
DMA_SetCurrDataCounter(DMA1_Channel6,CMD_RX_Buf_Len); // 重新设置传输的数据数量
DMA_Cmd(DMA1_Channel6,ENABLE); // 开启DMA传输
USART_ReceiveData(USART2); // 读取一次数据,不然会一直进中断
USART_ClearFlag(USART2,USART_FLAG_IDLE); // 清除串口空闲中断标志位
}
}