4组串口UART使用DMA收发

4组串口UART使用DMA收发

4组串口UART使用DMA收发, 精品实战代码, 易用,高效,稳定 !
源自实际系统 @STC32G12K128系列
非常容易使用, 将C文件添加至项目, 初始化后, 即可用.
3个函数,包含一切UART串口操作,适用90%以上场景 !
===从此告别串口驱动代码开发.
void UART1_Init(u32 btl); //初始化串口
u8 UART1_Send(void *pt, u16 Size); //发送数据
u16 UART1_Receive(u8 *buf, u16 Size); //接收数据

main() 函数演示 4个串口同时使用 DMA 收发数据, 收到数据后原路返回, 不限数据长度, 持续收发.

主要收发函数使用说明:
/**
* 原型: u8 UART1_Send( void *pt, u16 Size);
* @功能 串口发送数据. 写数据至发送缓冲区(循环池), 写完立即返回, 由DMA管理数据流向串口,
用户无须关心. 只要缓冲区有足够的空间, 可持续写入数据
* @参数 pt: 发送数据指针
* @参数 Size: 发送数量(字节)
* @返回值 当缓冲区没有足够的空间装入数据时返回1, 其它时候返回0
*/

/**
* 原型: u16 UART1_Receive(u8 *buf, u16 Size);
* @功能 读串口数据, 从缓冲区内读取数据. (DMA接收数据后存放至接收缓冲区,
应用代码必须定时查询读取, 否则循环池发生数据覆盖, 会丢失一部分数据, 没有提示, 但不影响后续收发)
* @参数 buf: 接收数据指针
* @参数 Size: Size期盼接收的字节数
* @返回值 实际接收字节数. 缓冲区空时(没有数据可读)返回0, 返回值<Size说明本次读取完成后,缓冲区已空.
返回值==Size说明本次读取完成后,缓冲区仍有数据可读. 任何时候,返回值不会大于Size
*/

/*---------------------------------------------------------
MAIN.C

main 函数演示 4个串口同时使用 DMA 收发数据, 收到数据后原路返回, 不限数据长度, 持续收发.

例程中所有串口9600波特率,默认引脚,定时器2作为波特率发生器
----------------------------------------------------------*/

#include "Config.h"
#include ".\library\STC32G_GPIO.h"
#include "UART1.h"
#include "UART2.h"
#include "UART3.h"
#include "UART4.h"

/*---------------------------------------------------------
本地函数声明
----------------------------------------------------------*/
void Timer0_Init(void);
void XOSCClkConfig(u8 div);
void GPIO_config(void);
void Delay1000ms();


/*---------------------------------------------------------
全局变量
----------------------------------------------------------*/
u8 ClockSignal=0;

/*---------------------------------------------------------
main
----------------------------------------------------------*/
void main(void)
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXSFR(); //扩展SFR(XFR)访问使能
CKCON = 0; //提高访问XRAM速度

GPIO_config(); //GPIO 初始化

#if USE_Extern_Fosc
XOSCClkConfig(1); //切换时钟
#endif

UART1_Init(9600); //串口1 初始化
UART2_Init(9600); //串口1 初始化
UART3_Init(9600); //串口1 初始化
UART4_Init(9600); //串口1 初始化
Timer0_Init(); //Timer0 初始化
EA = 1;

Delay1000ms(); //等待1秒, PC端下载代码,1秒自动打开CDC串口

printf("STC32G_UART_DEMO"); //打印信到CDC

while(1)
{
if(ClockSignal>0)
{
u8 uart_dat[32],len;


ClockSignal--;

//串口1接收,发送
do{
len = UART1_Receive(uart_dat,32); //读串口1收到的数据
UART1_Send(uart_dat,len); //串口1发送读到的数据
}while(len==32);

//串口2接收,发送
do{
len = UART2_Receive(uart_dat,32); //读串口2收到的数据
UART2_Send(uart_dat,len); //串口2发送读到的数据
}while(len==32);

//串口3接收,发送
do{
len = UART3_Receive(uart_dat,32); //读串口3收到的数据
UART3_Send(uart_dat,len); //串口3发送读到的数据
}while(len==32);

//串口4接收,发送
do{
len = UART4_Receive(uart_dat,32); //读串口4收到的数据
UART4_Send(uart_dat,len); //串口4发送读到的数据
}while(len==32);

}
}
}

/*---------------------------------------------------------
GPIO_config
----------------------------------------------------------*/
void GPIO_config(void)
{
P0_MODE_IO_PU(GPIO_Pin_All); //P0 设置为准双向口
P1_MODE_IO_PU(GPIO_Pin_All); //P1 设置为准双向口
P2_MODE_IO_PU(GPIO_Pin_All); //P2 设置为准双向口
P3_MODE_IO_PU(GPIO_Pin_All); //P3 设置为准双向口
P4_MODE_IO_PU(GPIO_Pin_All); //P4 设置为准双向口
P5_MODE_IO_PU(GPIO_Pin_All); //P5 设置为准双向口
P6_MODE_IO_PU(GPIO_Pin_All); //P6 设置为准双向口
P7_MODE_IO_PU(GPIO_Pin_All); //P7 设置为准双向口
P7_MODE_IO_PU(GPIO_Pin_All); //P7 设置为准双向口
}

/*-----------------------------------------------------------*
Timer0_Init
*-----------------------------------------------------------*/
#define OS_TICKS_PER_SEC 50u /*指定滴答时钟频率,宏自动计算装载值*/
#define TM0PS_VALUE ( MAIN_Fosc / OS_TICKS_PER_SEC / 65536UL )
#define RELOAD_VALUE ( 65536UL - MAIN_Fosc / (TM0PS_VALUE+1U) / OS_TICKS_PER_SEC )
void Timer0_Init(void)
{
AUXR |= 0x80; //1T模式
TMOD &= 0XF0; //模式0
TM0PS = TM0PS_VALUE; //分频系数
TL0 = ( uint8_t )( RELOAD_VALUE ); //装载值
TH0 = ( uint8_t )( RELOAD_VALUE >> 8 ); //装载值
TF0 = 0; //清除标志
ET0 = 1; //使能中断
TR0 = 1; //定时器开启
}

/*---------------------------------------------------------
外部晶振时钟初始化程序. div: 时钟分频系数.
----------------------------------------------------------*/
#if USE_Extern_Fosc
void XOSCClkConfig(u8 div)
{
P1_MODE_IN_HIZ(GPIO_Pin_7|GPIO_Pin_6); //GPIO设置
XOSCCR = 0xC0; //启动外部晶振
while (!(XOSCCR & 1)); //等待时钟稳定
CLKDIV = div; //时钟分频
CLKSEL = 0x01; //选择外部晶振
}
#endif


/*---------------------------------------------------------
Timer0 中断
----------------------------------------------------------*/
void Timer0_ISR_Handler (void) interrupt TMR0_VECTOR //进中断时已经清除标志
{
ClockSignal++;
}

/*---------------------------------------------------------
Delay1000ms
----------------------------------------------------------*/
void Delay1000ms() //@11.0592MHz
{
unsigned long edata i;

_nop_();
_nop_();
i = 2764798UL;
while (i) i--;
}