news 2026/7/3 21:19:02

4组串口UART使用DMA收发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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--;
}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/3 21:01:51

STM32F415RG与ICM-45605构建高精度IMU系统指南

1. 项目背景与核心器件选型在嵌入式系统开发中&#xff0c;精确测量物体的运动状态是一个常见但极具挑战性的需求。ICM-45605作为TDK InvenSense最新推出的6轴MEMS IMU传感器&#xff0c;配合STM32F415RG这款高性能ARM Cortex-M4微控制器&#xff0c;能够构建一个高精度、低功耗…

作者头像 李华
网站建设 2026/7/3 20:56:26

S1.2 从0到1000用户:独立产品的冷启动实战

从0到1000用户&#xff1a;独立产品的冷启动实战导读&#xff1a;没有营销预算&#xff0c;没有团队支持&#xff0c;如何让你的产品被第一批用户发现&#xff1f;一个真实案例 2024年3月&#xff0c;独立开发者小李上线了一个Markdown笔记工具。 没有推广预算&#xff0c;没有…

作者头像 李华
网站建设 2026/7/3 20:55:20

MIC1557+STM32F207ZG高精度定时方案设计与实现

1. 为什么选择MIC1557STM32F207ZG组合&#xff1f;在工业控制和嵌入式系统中&#xff0c;定时精度和可靠性往往直接决定整个系统的稳定性。我最近在一个自动化产线控制项目中&#xff0c;就遇到了传统定时方案带来的困扰——RC振荡电路受温度影响大&#xff0c;而普通晶振在电磁…

作者头像 李华
网站建设 2026/7/3 20:50:29

2026证件照换背景指南:手机APP、电脑工具与免费无水印方案

求职报名、证件办理、学籍登记等场景中&#xff0c;不同机构对证件照底色的要求各有不同&#xff0c;专程跑照相馆重做既耗时间又增加成本。其实借助日常常用的手机软件、电脑工具或是轻量线上服务&#xff0c;自行完成证件照换背景并不复杂。2026 年可选用的工具覆盖了从免费应…

作者头像 李华