Electricity/FWLIB/source/ENS1_UART.c

402 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*Copyright (C),2023 , NANOCHAP
*File name: ENS1_UART.C
*Author:
*Version: V1.0
*Date: 2023-11-
*Description:
*Function List:
History:
1.V1.0
Date:
Author:
Modification: 初版
*/
/*
ENS1 uart特性说明
1 符合AMBA APB规范
2 最高115200bps波特率(可以有更高的设置)
3 发送 接收 分离FIFO 16字节
4 支持自动流控
5 标准异步通信位(开始、停止、奇偶校验)
6 DMA
7 支持回环测试
8 中断
9 全可编程串行接口特点:
数据位可设置: 5678
偶、奇或非奇偶位的生成和检测
可产生1、1.5或2位停止位
*/
#include "my_header.h"
#include "ENS1_UART.h"
#include "ENS1_GPIO.h"
UART_FifoStructrue UART1_Fifo = {
.level = bytes_8 ,
.DMA_Enable =0 ,
.FIFO_Enable =1 ,
};
UART_InitStructure UART1_Init = {
.UART_BaudRate = 110000 , //计算出来的DLL DLH不为整数 1、需要校准RC精确度2、需要调整此处的波特率
.UART_HardwareFlowControl =0,
.FifoSetting = &UART1_Fifo ,
.stop_len = StopLen_1, //固定停止位1位
.Word_len = WordLen_8, //数据位8位
.Stick_EN = Stick_RESET, //禁用固定奇偶校验
.Even_EN = Even_SET, //奇偶校验选择
.Parity_EN = Parity_RESET, //禁用奇偶检验
};
UART_ITStructure UART1_ITSet = {
.UartIntModel = RLSI_EN | RDAI_EN ,
};
/*判断是否有中断挂起*/
uint8_t UART_INT_PEND(CMSDK_UART_TypeDef* UARTx) //为0时有UART的中断挂起
{
return (uint8_t)(UARTx->IIR & 0x1);
}
/*中断类型判断*/
uint8_t UART_INT_TYPE(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((UARTx->IIR >> 1) & 0x7 );
}
/*fifo 使用指示器*/
uint8_t UART_FIFO_USE(CMSDK_UART_TypeDef* UARTx) //0:非fifo模式 1fifo 使能
{
return (uint8_t)((UARTx->IIR >> 6) & 0x3);
}
/*清除传输FIFO*/
void UART_TXCLR(CMSDK_UART_TypeDef* UARTx)
{
UARTx->FCR |= (1<<2) ;
}
/*清除接收FIFO*/
void UART_RXCLR(CMSDK_UART_TypeDef* UARTx)
{
UARTx->FCR |= (1<<1);
}
/*FIFO使能*/
void UART_FIFOEnable(CMSDK_UART_TypeDef* UARTx)
{
UARTx->FCR |= (1);
}
/*FIFO关闭*/
void UART_FIFODisable(CMSDK_UART_TypeDef* UARTx)
{
UARTx->FCR &=~ 1;
}
/*接收数据*/
uint8_t READ_UART_RCVBuff(CMSDK_UART_TypeDef* UARTx )
{
return (uint8_t)(UARTx->RBR & 0xff);
}
/*发送数据*/
void WRITE_UART_THRBuff(CMSDK_UART_TypeDef* UARTx ,uint8_t data)
{
UARTx->THR = data;
}
/*FIFO 状态读取*/
uint8_t UART_RX_FIFO_LEN(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((UARTx->FSR & 0x001f0000)>>16); //读取当前接收FIFO数据长度
}
uint8_t UART_TX_FIFO_LEN(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((UARTx->FSR & 0x00001f00)>>8); //读取当前发送FIFO数据长度
}
uint8_t UART_RX_FIFO_FULL(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((((UARTx->FSR & 0x8)>> 3 )==1) ? (1) : (0)) ; //当前读取FIFO是否为满
}
uint8_t UART_RX_FIFO_EMPTY(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((((UARTx->FSR & 0x4) >> 2)==1) ? (1) : (0) ) ; //当前读取FIFO是否为空
}
uint8_t UART_TX_FIFO_FULL(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((((UARTx->FSR & 0x2) >> 1)==1) ? (1) : (0)) ; //当前发送FIFO是否为满
}
uint8_t UART_TX_FIFO_EMPTY(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)(((UARTx->FSR & 0x1)==1) ? (1) : (0)) ; //当前发送FIFO是否为空
}
/*收发线状态获取*/
uint8_t UARTLine_RCVError(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((UARTx->LSR>>7) & 0x1); //返回0 没有错误, 返回1 在fifo和非fifo状态下都有一个校验/帧/或接收缓存或fifo 的中断指示默认不使能break
}
/*判断发送缓存是否为空*/
uint8_t UARTLine_TRANSEmpty(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((UARTx->LSR>>6) & 0x1) ;
}
/*判断THR是否为空*/
uint8_t UARTLine_THREmpty(CMSDK_UART_TypeDef* UARTx)
{
return (uint8_t)((UARTx->LSR>>5) & 0x1) ;
}
/*
初始化UART需要以下步骤:
1. 执行必要的设备引脚多路复用设置。
2. 通过将适当的时钟除数值写入除数锁存寄存器(DLL和DLH)来设置所需的波特率。
3. 如果要使用FIFO请选择所需的触发等级并通过将适当的值写入(FCR)来启用FIFO。
在FCR寄存器的 FIFOEN 位需首先配置。
4. 通过向行控制寄存器(LCR)写入适当的值来选择所需的协议设置。
5. 如果需要自动流量控制,则将适当的值写入调制解调器控制寄存器(MCR)。
请注意并非所有uart都支持自动流量控制。
6. 对挂起事件的选择所需响应通过配置FREE位
通过在(PMU)寄存器中设置TXRST和RXRST位来释放位并使能UART
*/
//uart初始化参数1uart0/1参数2uart参数设置结构体
void UART_Init(CMSDK_UART_TypeDef *CMSDK_UART, UART_InitStructure* uart_paraX){
uint16_t divisor_value;
uint8_t overSamp_mode;
/* 1 GPIO - alt_function*/
if(CMSDK_UART == CMSDK_UART0){
PCLK_Enable(UART0_PCLK_EN);
GPIO_AltFunction(UART0_RX , ALT_FUNC1); //rx
GPIO_AltFunction(UART0_TX , ALT_FUNC1); //tx
// 修复正确配置GPIO方向
// GPIO2 (RX) 应该是输入
CMSDK_GPIO->OE &= ~(1 << UART0_RX); // 禁用输出
CMSDK_GPIO->IE |= (1 << UART0_RX); // 使能输入
// GPIO3 (TX) 应该是输出
CMSDK_GPIO->IE &= ~(1 << UART0_TX); // 禁用输入
CMSDK_GPIO->OE |= (1 << UART0_TX); // 使能输出
}
else if(CMSDK_UART == CMSDK_UART1)
{
PCLK_Enable(UART1_PCLK_EN);
GPIO_AltFunction(UART1_RX , ALT_FUNC1); //RX
GPIO_AltFunction(UART1_TX , ALT_FUNC1); //TX
// 修复正确配置GPIO方向
// GPIO12 (RX) 应该是输入
CMSDK_GPIO->OE &= ~(1 << UART1_RX); // 禁用输出
CMSDK_GPIO->IE |= (1 << UART1_RX); // 使能输入
// GPIO13 (TX) 应该是输出
CMSDK_GPIO->IE &= ~(1 << UART1_TX); // 禁用输入
CMSDK_GPIO->OE |= (1 << UART1_TX); // 使能输出
// 确保TX引脚初始化为高电平
CMSDK_GPIO->DATAOUT |= (1 << UART1_TX);
}
/* 2 波特率设置*/
if(((CMSDK_UART->MDR)&0x00000001) == 0)
{
overSamp_mode = 16; //默认0
}
else
{
overSamp_mode = 13;
}
//波特率校准反推处DLL和DLH外设时钟主频/设置波特率/过采样模式)-1
divisor_value = (uint16_t)((uint32_t)(APB_Clock_Freq / uart_paraX->UART_BaudRate / overSamp_mode) - 1);
CMSDK_UART->DLL = (uint8_t)(divisor_value & 0x00FF);
CMSDK_UART->DLH = (uint8_t)((divisor_value & 0xFF00)>>8);
/*FCR配置 FIFO control*/
CMSDK_UART->FCR |= (uart_paraX->FifoSetting->level <<6);//接收多少字节后触发中断
if(uart_paraX->FifoSetting->FIFO_Enable == 1)
{
CMSDK_UART->FCR |= (1);
}
//配置停止位
CMSDK_UART->LCR &= ~(0x01 << 2);
CMSDK_UART->LCR |= uart_paraX->stop_len<<2;
//配置数据位
CMSDK_UART->LCR &= ~(0x03 << 0);
CMSDK_UART->LCR |= uart_paraX->Word_len<<0;
//配置是否启用校验位
CMSDK_UART->LCR &= ~(0x01 << 3);
CMSDK_UART->LCR |= uart_paraX->Parity_EN<<3;
//启用校验位
if(uart_paraX->Parity_EN==Parity_SET)
{
CMSDK_UART->LCR &= ~(0x03 << 4);
CMSDK_UART->LCR |= uart_paraX->Even_EN<<4;
CMSDK_UART->LCR |= uart_paraX->Stick_EN<<5;
}
/*MCR自动流控配置*/
if(uart_paraX->UART_HardwareFlowControl == 1)
{
CMSDK_UART->MCR |= (1<<5);
}
/*电源管理寄存器PMU 的TXRST和RXRST设置,不需要设置*/
}
/*UART 的中断设置*/
void UART_ITConfig(CMSDK_UART_TypeDef *CMSDK_UART, UART_ITStructure* uart_paraX)
{
if(CMSDK_UART == CMSDK_UART1){
NVIC_DisableIRQ(UART1_IRQn);//Disable NVIC interrupt
NVIC_ClearPendingIRQ(UART1_IRQn);//Clear Pending NVINVIC_EnableIRQ(UART1_IRQn);//Enable NVIC interrupt
}
else if(CMSDK_UART == CMSDK_UART0){
NVIC_DisableIRQ(UART0_IRQn);//Disable NVIC interrupt
NVIC_ClearPendingIRQ(UART0_IRQn);//Clear Pending NVIC interrupt
}
/*IER配置中断使能寄存器*/
CMSDK_UART->IER |= (uart_paraX->UartIntModel);
if(CMSDK_UART == CMSDK_UART1){
NVIC_EnableIRQ(UART1_IRQn);
}
else if(CMSDK_UART == CMSDK_UART0){
NVIC_EnableIRQ(UART0_IRQn);
}
}
unsigned char UartPutc(CMSDK_UART_TypeDef *CMSDK_UART ,unsigned char my_ch)
{
while (UARTLine_THREmpty(CMSDK_UART) == 0x0);
WRITE_UART_THRBuff(CMSDK_UART,my_ch);
return (my_ch);
}
//串口发送一定字节的数据
void Uart_Send(CMSDK_UART_TypeDef *CMSDK_UART ,uint8_t *data, uint8_t len)
{
uint8_t t;
for(t=0;t<len;t++) //循环发送数据
{
while(UARTLine_THREmpty(CMSDK_UART) == 0x0);//等待发送结束
WRITE_UART_THRBuff(CMSDK_UART,data[t]);
}
while(UARTLine_THREmpty(CMSDK_UART) == 0x0);//等待发送结束
}
/*
中断与中断状态清除
1 接收线状态INT_RCV_LINE_STATUS
溢出、校验、帧错误或检测到break
中断清除方式对于溢出错误读取LSR 可清除中断对于校验、帧错误或break中断需要等待所有的错误数据被读取后才被清除
2 接收数据就绪: INT_RCV_DATA_AVAILABLE
非FIFO模式下接收数据准备就绪 fifo模式下达到触发阈值如果四个字节时间内没有访问FIFO ,就再次触发
中断清除方式非FIFO模式下RBR被读取 FIFO模式下FIFO低于触发阈值被清除
3 接收超时INT_CHAR_TIMEOUT_INDICATION
仅仅FIFO模式有效 在最后四个字节的时间内没有字符从接收器FIFO 中移除或者输入并且在此期间接收器FIFO中至少有一个字符
中断清除方式11个字节从接收FIFO中被读出 2一个新的字节到达接收FIFO 3PMU寄存器中的URRST 位置1
4 传输保持寄存器空THR INT_THR_EMPTY
非FIFO模式下 THR空。 FIFO模式下传输器FIFO空
中断清除方式:一个字节被写到 THR
*/
void UART0_Handler(void) {
uint8_t rev_data = 0;
NVIC_ClearPendingIRQ(UART0_IRQn);
//接收线中断 有错误或者break
if(UART_INT_TYPE(CMSDK_UART0) == INT_RCV_LINE_STATUS) {
CMSDK_UART0->IER &= ~CMSDK_UART_IER_RLSI_EN_Msk;
}
//数据就绪中断
//接收超时中断
if((UART_INT_TYPE(CMSDK_UART0) == INT_RCV_DATA_AVAILABLE) || (UART_INT_TYPE(CMSDK_UART0) == INT_CHAR_TIMEOUT_INDICATION))
{
CMSDK_UART0->IER &= ~CMSDK_UART_IER_RDAI_EN_Msk;
rev_data = CMSDK_UART0->RBR;
UartPutc(CMSDK_UART0,rev_data);
CMSDK_UART0->IER |= CMSDK_UART_IER_RDAI_EN_Msk;
}
return;
}
// 外部变量声明在main.c中定义
uint8_t uart_rx_buffer[64];
uint8_t uart_rx_count;
volatile uint8_t uart_data_ready;
// 外部函数声明
extern uint8_t ParseUART_EMS_Packet(uint8_t *data, uint16_t length, void *packet);
extern void UpdateEMS_ConfigFromUART(void *packet);
// 数据包结构体定义
void UART1_Handler(void) {
uint8_t rev_data = 0;
uint32_t ParamNumber = 0;
// 清除NVIC中断挂起位
NVIC_ClearPendingIRQ(UART1_IRQn);
// 检查中断类型
uint8_t int_type = UART_INT_TYPE(CMSDK_UART1);
// 接收线中断 - 有错误或者break
if(int_type == INT_RCV_LINE_STATUS) {
// 读取LSR寄存器清除错误状态
uint32_t lsr = CMSDK_UART1->LSR;
(void)lsr; // 避免未使用变量警告
}
// 数据就绪中断或接收超时中断
if((int_type == INT_RCV_DATA_AVAILABLE) || (int_type == INT_CHAR_TIMEOUT_INDICATION)) {
ParamNumber = (CMSDK_UART1->FSR >> 16) & 0x1f;
for(uint32_t i = 0; i < ParamNumber; i++) {
rev_data = CMSDK_UART1->RBR; // 把接收到的数据取出来
// 将数据存储到缓冲区
if(uart_rx_count < sizeof(uart_rx_buffer)) {
uart_rx_buffer[uart_rx_count] = rev_data;
uart_rx_count++;
} else {
// 缓冲区溢出,重置
uart_rx_count = 0;
}
UartPutc(CMSDK_UART1, rev_data); // 把接收到的数据再发回去
}
// 检查是否收到完整数据包19字节
if(uart_rx_count >= 19) {
//printf("1");
// 解析数据包
UART_EMS_Packet_t ems_packet;
if(ParseUART_EMS_Packet(uart_rx_buffer, uart_rx_count, &ems_packet)) {
// 更新电刺激配置
UpdateEMS_ConfigFromUART(&ems_packet);
} else {
}
// 清除缓冲区
uart_rx_count = 0;
}
}
return;
}