Files
BLV_MD203_Bootload/Source/SYSTEM/uart.c
caocong 2815979c8a fix:修改RS485通讯引脚
RS485通讯引脚改为串口2,引脚:RX:PB05 TX:PB04 RS485_DR:PB03
2026-02-25 10:29:57 +08:00

628 lines
17 KiB
C
Raw 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.
#include "includes.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/**
* Bootload 串口使用情况
* UART0 没有使用
* UART2 用与调试信息输出 - 512000
* UART1 用于Bootload 升级使用
* */
UART_t g_uart; //目前该项目只使用串口2 进行双向通讯
MULIT_t m_send;
void UARTx_Init(UART_IDX uart_id, Uart_prt prt_cf) {
switch(uart_id){
case UART_1:
memset(&g_uart,0,sizeof(UART_t));
memset(&m_send,0,sizeof(MULIT_t));
//串口1-RX接收中断用于串口1的通讯总线繁忙状态判断2025-04-16
// GPIO_PullHigh_Init(GPIOA0,15);
// GPIO_IntGroup_Set(PA0,15,Selete_EXI_PIN15); //EXI0 set PB0.2
// GPIOA0_EXI_Init(EXI15); //PB0.2 as input
// EXTI_trigger_CMD(ENABLE,EXI_PIN15,_EXIFT); //ENABLE falling edge
// EXTI_trigger_CMD(ENABLE,EXI_PIN15,_EXIRT);
// EXTI_interrupt_CMD(ENABLE,EXI_PIN15); //enable EXI
// GPIO_EXTI_interrupt(GPIOA0,0b1000000000000000); //enable GPIOB02 as EXI
// EXI4_Int_Enable();
//
// UART1_DeInit(); //clear all UART Register
// UART_IO_Init(IO_UART1,2); //use PA0.13->RXD1, PB0.0->TXD1
// UARTInitRxTxIntEn(UART1,20000,UART_PAR_NONE); //baudrate=sysclock 48M/20000=2400 tx rx int enabled
// UART1_Int_Enable();
//
// m_send.BusState_Tick = SysTick_1ms;
// m_send.HighBit_Flag = 0x01;
//
// g_uart.RecvTimeout = Recv_2400_TimeOut;
// g_uart.processing_cf = prt_cf;
//
// //485使能引脚初始化
// GPIO_Init(GPIOA0,UART485_DR_PIN,Output);
// GPIO_DriveStrength_EN(GPIOA0,UART485_DR_PIN);
// WRITE_LOW_DR;
break;
case UART_2:
//2026-02-06 使用串口2作为Bootload 升级使用
memset(&g_uart,0,sizeof(UART_t));
memset(&m_send,0,sizeof(MULIT_t));
//串口RX接收中断
GPIO_PullHigh_Init(GPIOB0,5);
GPIO_IntGroup_Set(PB0,5,Selete_EXI_PIN5); //EXI0 set PB0.5
GPIOB0_EXI_Init(EXI5); //PB0.5 as input
EXTI_trigger_CMD(ENABLE,EXI_PIN5,_EXIFT); //ENABLE falling edge
EXTI_trigger_CMD(ENABLE,EXI_PIN5,_EXIRT);
EXTI_interrupt_CMD(ENABLE,EXI_PIN5); //enable EXI
GPIO_EXTI_interrupt(GPIOB0,0b0000000000100000); //enable GPIOB05 as EXI
EXI3_Int_Enable(); //EXI4~EXI9 INT Vector
UART2_DeInit(); //clear all UART Register
UART_IO_Init(IO_UART2,2); //use PA0.13->RXD1, PB0.0->TXD1
UARTInitRxTxIntEn(UART2,20000,UART_PAR_NONE); //baudrate=sysclock 48M/416=115200 tx rx int enabled
UART2_Int_Enable();
m_send.BusState_Tick = SysTick_1ms;
m_send.HighBit_Flag = 0x01;
g_uart.RecvTimeout = Recv_2400_TimeOut;
g_uart.processing_cf = prt_cf;
//485使能引脚初始化
GPIO_Init(GPIOB0,3,Output);
GPIO_DriveStrength_EN(GPIOB0,3);
WRITE_LOW_DR;
break;
}
}
/*******************************************************************************
* Function Name : Get_Uart_BaudCnt
* Description : Uart 获取串口波特率对于设置值
*******************************************************************************/
U16_T Get_Uart_BaudCnt(U32_T baud)
{
switch(baud){
case 2400:
return 20000;
case 4800:
return 10000;
case 9600:
return 5000;
case 19200:
return 2621;
case 56000:
return 898;
case 115200:
return 416;
case 512000:
return 98;
}
return 0x00;
}
/*******************************************************************************
* Function Name : Get_Uart_Recv_Timeout
* Description : Uart 获取串口接收超时时间
*******************************************************************************/
U32_T Get_Uart_Recv_Timeout(U32_T baud)
{
switch(baud){
case 2400:
return Recv_2400_TimeOut;
case 4800:
return Recv_2400_TimeOut;
case 9600:
return Recv_9600_TimeOut;
case 19200:
return Recv_9600_TimeOut;
case 56000:
return Recv_9600_TimeOut;
case 115200:
return Recv_115200_TimeOut;
case 512000:
return Recv_115200_TimeOut;
}
return Recv_115200_TimeOut;
}
/*******************************************************************************
* Function Name : UARTx_ChangeBaud
* Description : Uart 切换串口波特率
*******************************************************************************/
U8_T UARTx_ChangeBaud(uint8_t uart_id,uint32_t baud)
{
U16_T set_para = Get_Uart_BaudCnt(baud);
if(set_para == 0x00) return 0x01; //设置的波特率不支持
switch(uart_id){
case UART_1:
#if DBG_LOG_EN
Dbg_Println(DBG_BIT_SYS_STATUS, "UART ID %d", uart_id);
Dbg_Println(DBG_BIT_SYS_STATUS,"UART baud %d",baud);
#endif
UARTClose(UART1);
UART1_Int_Disable();
UART1_DeInit(); //clear all UART Register
UART_IO_Init(IO_UART1,2); //use PA0.13->RXD1, PB0.0->TXD1
UARTInitRxTxIntEn(UART1,set_para,UART_PAR_NONE); //baudrate=sysclock 48M/416=115200 tx rx int enabled
UART1_Int_Enable();
g_uart.RecvTimeout = Get_Uart_Recv_Timeout(baud);
break;
case UART_2:
UARTClose(UART2);
UART2_Int_Disable();
UART2_DeInit(); //clear all UART Register
UART_IO_Init(IO_UART2,2); //use PA0.13->RXD1, PB0.0->TXD1
UARTInitRxTxIntEn(UART2,set_para,UART_PAR_NONE); //baudrate=sysclock 48M/416=115200 tx rx int enabled
UART2_Int_Enable();
g_uart.RecvTimeout = Get_Uart_Recv_Timeout(baud);
break;
}
}
/*******************************************************************************
* Function Name : UART1_RecvINT_Processing
* Description : 串口1 接收中断处理函数 - 接收中断调用
*******************************************************************************/
//void UART1_RecvINT_Processing(char data){
// if((g_uart.RecvLen + 1) >= USART_BUFFER_SIZE) g_uart.RecvLen = 0;
// g_uart.RecvBuffer[g_uart.RecvLen++] = (U8_T)data;
//
// g_uart.RecvIdleTiming = SysTick_1ms;
// g_uart.Receiving = 0x01;
//}
//
//
//void UART1_TASK(void){
// U8_T ret = 0x00;
// if(g_uart.Receiving == 0x01){
// if(SysTick_1ms - g_uart.RecvIdleTiming > g_uart.RecvTimeout){
//
// SYSCON_Int_Disable();
// g_uart.RecvIdleTiming = SysTick_1ms;
// memcpy(g_uart.DealBuffer,g_uart.RecvBuffer,g_uart.RecvLen);
// g_uart.DealLen = g_uart.RecvLen;
// g_uart.RecvLen = 0;
// g_uart.Receiving = 0;
// SYSCON_Int_Enable();
//
//#if DBG_LOG_EN
// Dbg_Println(DBG_BIT_SYS_STATUS, "UART recv Len %d", g_uart.DealLen);
// Dbg_Print_Buff(DBG_BIT_SYS_STATUS,"UART buff",g_uart.DealBuffer,g_uart.DealLen);
//#endif
//
// if(g_uart.processing_cf != NULL){
// ret = g_uart.processing_cf(g_uart.DealBuffer,g_uart.DealLen);
// }
//
// }
// }
//}
/*******************************************************************************
* Function Name : UART2_RecvINT_Processing
* Description : 串口2 接收中断处理函数 - 接收中断调用
*******************************************************************************/
void UART2_RecvINT_Processing(char data){
if((g_uart.RecvLen + 1) >= USART_BUFFER_SIZE) g_uart.RecvLen = 0;
g_uart.RecvBuffer[g_uart.RecvLen++] = (U8_T)data;
g_uart.RecvIdleTiming = SysTick_1ms;
g_uart.Receiving = 0x01;
}
void UART2_TASK(void){
U8_T ret = 0x00;
if(g_uart.Receiving == 0x01){
if(SysTick_1ms - g_uart.RecvIdleTiming > g_uart.RecvTimeout){
SYSCON_Int_Disable();
g_uart.RecvIdleTiming = SysTick_1ms;
memcpy(g_uart.DealBuffer,g_uart.RecvBuffer,g_uart.RecvLen);
g_uart.DealLen = g_uart.RecvLen;
g_uart.RecvLen = 0;
g_uart.Receiving = 0;
SYSCON_Int_Enable();
#if DBG_LOG_EN
Dbg_Println(DBG_BIT_SYS_STATUS, "UART recv Len %d", g_uart.DealLen);
Dbg_Print_Buff(DBG_BIT_SYS_STATUS,"UART buff",g_uart.DealBuffer,g_uart.DealLen);
#endif
if(g_uart.processing_cf != NULL){
ret = g_uart.processing_cf(g_uart.DealBuffer,g_uart.DealLen);
}
}
}
}
/*因为开启了UART_TX_DONE_S 中断,发送完成需要清楚该中断标志位,因此每次调用串口输出后,需调用该函数,否则会在中断出不来
* 已取消
* */
void UART_Waiting_For_Send(CSP_UART_T *uart){
unsigned int Dataval = 0,delay_cnt = 0;
do{
Dataval = CSP_UART_GET_ISR(uart);
Dataval = Dataval & UART_TX_DONE_S;
delay_cnt ++;
if(delay_cnt >= 50000){
break;
}
}while(Dataval == 0x00); //发送完成
uart->ISR=UART_TX_DONE_S;
}
volatile int RS485_Comm_Flag = 0,RS485_Comm_Start = 0,RS485_Comm_End = 0,RS485_Comming = 0;
void MCU485_SendData(U8_T *buff,U16_T len){
unsigned int Dataval = 0,delay_cnt = 0;
//等待通讯发送完成
while(RS485_Comming == 0x01){
delay_nus(100);
delay_cnt ++;
if(delay_cnt >= 100){
break;
}
REVERISE_DR;//GPIO_Reverse(GPIOB0,3);
}
WRITE_HIGH_DR;//GPIO_Write_High(GPIOB0,3);
RS485_Comm_Flag = 0x01;
RS485_Comm_Start = 0x00;
RS485_Comm_End = 0x00;
UARTTransmit(UART2,buff,len);
do{
delay_nus(100);
delay_cnt ++;
if(delay_cnt >= 100){
break;
}
}while((RS485_Comm_Start < len) || (RS485_Comm_End < len)); //发送完成
WRITE_LOW_DR;//GPIO_Write_Low(GPIOB0,3);
RS485_Comm_Flag = 0x00;
}
/**********************************************************
* @brief BUS485 数据发生函数 - 检测总线是否繁忙,空闲状态下,才发生数据;繁忙状态下,直接退出
* @retval None
* */
U8_T BUS485_Send(U8_T *buff,U16_T len)
{
unsigned int Dataval = 0,delay_cnt = 0;
//等待通讯发送完成
while(RS485_Comming == 0x01){
delay_nus(100);
delay_cnt ++;
if(delay_cnt >= 100){
break;
}
REVERISE_DR;//GPIO_Reverse(GPIOB0,3);
}
if(m_send.BusState_Flag == UART_BUSIDLE){ //总线空闲
CK_CPU_DisAllNormalIrq();
WRITE_HIGH_DR;//GPIO_Write_High(GPIOB0,3);
RS485_Comm_Flag = 0x01;
RS485_Comm_Start = 0x00;
RS485_Comm_End = 0x00;
m_send.BusState_Flag = UART_BUSBUSY;//发送前总线置位繁忙
m_send.BUSBUSY_LOCK = 0x01; //锁定总线状态
CK_CPU_EnAllNormalIrq();
UARTTransmit(UART2,buff,len);
do{
delay_nus(100);
delay_cnt ++;
if(delay_cnt >= 100){
break;
}
}while((RS485_Comm_Start < len) || (RS485_Comm_End < len)); //发送完成
CK_CPU_DisAllNormalIrq();
WRITE_LOW_DR;//GPIO_Write_Low(GPIOB0,3);
RS485_Comm_Flag = 0x00;
m_send.BusState_Tick = SysTick_1ms;
m_send.BUSBUSY_LOCK = 0x00; //解锁总线状态
CK_CPU_EnAllNormalIrq();
return UART_BUSIDLE; //发送成功
}
else{ //总线繁忙
return UART_BUSBUSY; //发送失败
}
return 0x02; //传入状态无效
}
/**********************************************************
* @brief 重发、数据有效期、超时发送判断2025-03-25
* buff:发送数据
* len数据长度
* DatSd发送标记,0x00:无发送0x01有数据发送
*
* @retval 0x00:发送成功 0x01:等待发送 0x02:数据无效
* */
U8_T MultSend_Task(U8_T *buff,U16_T len,U8_T DatSd)
{
if( (len == 0)||(len > USART_BUFFER_SIZE) ) return LEN_ERR;
if(DatSd == 0x01)
{
if( m_send.ResendCnt < m_send.TotalCnt) //判断数据是否还在有效期,是否还有发送次数
{
if(SysTick_1ms - m_send.BusbusyTimeout < m_send.DataValid_Time)
{
if( (m_send.ResendCnt == 0x00) || (SysTick_1ms - m_send.ASend_Tick >= m_send.DataWait_Time) ){//数据发送间隔
if(BUS485_Send(buff,len) == UART_BUSIDLE){ //发送数据
m_send.ASend_Tick = SysTick_1ms;
m_send.ResendCnt++;
#if DBG_LOG_EN
Dbg_Println(DBG_BIT_Debug_STATUS,"SendCnt:%d success",m_send.ResendCnt);
#endif
return BUSSEND_SUCC;//数据发送成功
}
}
}else{
#if DBG_LOG_EN
Dbg_Println(DBG_BIT_Debug_STATUS,"data end");
#endif
return DATA_END;//数据有效期结束
}
}else{
#if DBG_LOG_EN
Dbg_Println(DBG_BIT_Debug_STATUS,"retry end,%d",m_send.ResendCnt );
#endif
return RETRY_END;//没有重发次数
}
}
return BUSSEND_WAIT;//等待
}
/**********************************************************
* @brief 设置发送标志、组包、选择数据有效期档位2025-03-25
* data: 发送数据
* sled 数据长度
* SCnt: 设置数据发送次数
* indate 设置数据有效期
* tim_val: 发送时间间隔
* @retval None
* */
void Set_GroupSend(U8_T *data,U16_T sled,U8_T SCnt,U32_T indate,U32_T tim_val)
{
if((sled == 0x00)|| (sled > USART_BUFFER_SIZE)) return;
memset(m_send.SendBuffer,0, USART_BUFFER_SIZE);
memcpy(m_send.SendBuffer,data,sled);
m_send.SendLen = sled;
m_send.DataValid_Time = indate;//数据有效期
m_send.TotalCnt = SCnt; //数据发送次数
m_send.DataWait_Time = tim_val;//发送数据间隔
m_send.ASend_Flag = 0x01;
m_send.ResendCnt = 0x00;
m_send.BusbusyTimeout = SysTick_1ms;
}
//清除发送标志
//void Clear_SendFlag(void)
//{
// m_send.ASend_Flag = 0x00;
//}
void BUS485_SetBaud(U32_T baud)
{
m_send.SetBaudFlag = 0x01;
m_send.SetBaud = baud;
}
/**********************************************************
* @brief 检测总线空闲在While(1)里调用 2025-03-25
* @retval None
* */
void BUS485Send_Task(void) //2025-03-29
{
U8_T ret = 0xFF;
//空闲等待
if(m_send.ASend_Flag == 0x01)//初始化发送
{
ret = MultSend_Task(m_send.SendBuffer,m_send.SendLen,m_send.ASend_Flag);
if( (ret == DATA_END)||(ret == RETRY_END) )//判断发送数据是否有效
{
#if DBG_LOG_EN
Dbg_Println(DBG_BIT_Debug_STATUS,"send end");
#endif
m_send.ASend_Flag = 0x00;
/*设置波特率*/
if( m_send.SetBaudFlag == 0x01 ){
UARTx_ChangeBaud(UART_2,m_send.SetBaud);
m_send.SetBaudFlag = 0x00;
m_send.SetBaud = 0x00;
}
}
}
}
/**********************************************************
* @brief 检测总线空闲,在定时器中断里调用
* @retval None
* */
void BusIdle_Task(void)
{
if(m_send.BusState_Flag != UART_BUSIDLE && m_send.BUSBUSY_LOCK != 0x01)
{
CK_CPU_DisAllNormalIrq();
if( ( m_send.HighBit_Flag == 0x01 )&&( ( SysTick_1ms - m_send.BusState_Tick ) >= ( g_uart.RecvTimeout + m_send.Bus_DelayTime )) )
{
m_send.BusState_Flag = UART_BUSIDLE;
}
CK_CPU_EnAllNormalIrq();
}
}
/*******************************************************************
* @brief 检测总线繁忙在串口接收RX引脚的外部中断服务函数里调用
* @retval None
* */
void BusBusy_Task(void)
{
CK_CPU_DisAllNormalIrq();
m_send.BusState_Flag = UART_BUSBUSY;
m_send.BusState_Tick = SysTick_1ms;
m_send.Bus_DelayTime = (SysTick_1ms - m_send.ASend_Tick)%10;//随机延时
if(READ_RXLEVEL_STATE == 0x01){
m_send.HighBit_Flag = 0x01; //高电平标志置位
}else if(READ_RXLEVEL_STATE == 0x00){
m_send.HighBit_Flag = 0x00; //低电平
}
CK_CPU_EnAllNormalIrq();
}
/*调试信息输出接口*/
U32_T Dbg_Switch = (DBG_OPT_Debug_STATUS << DBG_BIT_Debug_STATUS)
+ (DBG_OPT_DEVICE_STATUS << DBG_BIT_DEVICE_STATUS)
+ (DBG_OPT_SYS_STATUS << DBG_BIT_SYS_STATUS);
#if DBG_LOG_EN
char Dbg_Buffer[512] = {0};
U32_T SysTick_Now = 0, SysTick_Last = 0, SysTick_Diff = 0;
#endif
void Dbg_Print(int DbgOptBit, const char *cmd, ...){
#if DBG_LOG_EN
U16_T str_offset = 0;
if (Dbg_Switch & (1 << DbgOptBit)) {
SysTick_Now = SysTick_1ms;
SysTick_Diff = SysTick_Now - SysTick_Last; //上一次打印时间差
SysTick_Last = SysTick_Now;
str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer),"%8d [%6d]: ", SysTick_Now, SysTick_Diff);
DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
va_list args; //定义一个va_list类型的变量用来储存单个参数
va_start(args, cmd); //使args指向可变参数的第一个参数
str_offset = vsnprintf(Dbg_Buffer, sizeof(Dbg_Buffer) ,cmd, args); //必须用vprintf等带V的
va_end(args); //结束可变参数的获取
DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
}
#endif
}
void Dbg_Println(int DbgOptBit, const char *cmd, ...){
#if DBG_LOG_EN
U16_T str_offset = 0;
if (Dbg_Switch & (1 << DbgOptBit)) {
SysTick_Now = SysTick_1ms;
SysTick_Diff = SysTick_Now - SysTick_Last; //上一次打印时间差
SysTick_Last = SysTick_Now;
str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer) , "%8ld [%6ld]: ", SysTick_Now, SysTick_Diff);
DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
va_list args; //定义一个va_list类型的变量用来储存单个参数
va_start(args, cmd); //使args指向可变参数的第一个参数
str_offset = vsnprintf(Dbg_Buffer, sizeof(Dbg_Buffer) ,cmd, args); //必须用vprintf等带V的
va_end(args); //结束可变参数的获取
DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
DBG_Printf((U8_T *)"\r\n",2);
}
#endif
}
void Dbg_Print_Buff(int DbgOptBit, const char *cmd, U8_T *buff,U16_T len){
#if DBG_LOG_EN
U16_T str_offset = 0;
if (Dbg_Switch & (1 << DbgOptBit)) {
SysTick_Now = SysTick_1ms;
SysTick_Diff = SysTick_Now - SysTick_Last; //上一次打印时间差
SysTick_Last = SysTick_Now;
str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer) , "%8ld [%6ld]:%s ", SysTick_Now, SysTick_Diff,cmd);
DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
for (uint32_t i = 0; i < len; i++) {
SYSCON_IWDCNT_Reload();
str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer) , "%02X ", buff[i]);
DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
}
DBG_Printf((U8_T *)"\r\n",2);
}
#endif
}