串口DMA发送:
发送数据的流程:
前台程序中有数据要发送,则需要做如下几件事
1. 在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。
2. 将数据缓冲区内要发送的数据字节数赋值给发送DMA通道,(串口发送DMA和串口接收DAM不是同一个DMA通道)
3. 开启DMA,一旦开启,则DMA开始发送数据,说明一下:在KEIL调试好的时候,DMA和调试是不同步的,即不管Keil 是什么状态,DMA总是发送数据。
4. 等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循环查询也可以。或者其他方式。
判断数据发送完成:
启动DMA并发送完后,产生DMA发送完成中断,在中断函数中做如下几件事:
1. 清DMA发送完成中断标志位
2. 关闭串口发送DMA通道
3. 给前台程序设置一个软件标志位,说明数据已经发送完毕
串口DMA接收:
接收数据的流程:
串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。
判断数据数据接收完成:
这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事:
1. 关闭串口接收DMA通道,2点原因:1.防止后面又有数据接收到,产生干扰。2.便于DMA的重新配置赋值,下面第4点。
2. 清除DMA 所有标志位
3.从DMA寄存器中获取接收到的数据字节数
4.重新设置DMA下次要接收的数据字节数,注意,这里是给DMA寄存器重新设置接收的计数值,这个数量只能大于或者等于可能接收的字节数,否则当DMA接收计数器递减到0的时候,又会重载这个计数值,重新循环递减计数,所以接收缓冲区的数据则会被覆盖丢失。
5. 开启DMA通道,等待下一次的数据接收,注意,对DMA的相关寄存器配置写入,如第4条的写入计数值,必须要在关闭DMA的条件进行,否则操作无效。
说明一下,STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。
USART 和 DMA 硬件初始化配置
/*--- LumModule Usart Config ---*/
#define LUMMOD_UART USART3
#define LUMMOD_UART_GPIO GPIOC
#define LUMMOD_UART_CLK RCC_APB1Periph_USART3
#define LUMMOD_UART_GPIO_CLK RCC_APB2Periph_GPIOC
#define LUMMOD_UART_RxPin GPIO_Pin_11
#define LUMMOD_UART_TxPin GPIO_Pin_10
#define LUMMOD_UART_IRQn USART3_IRQn
#define LUMMOD_UART_DR_Base (USART3_BASE + 0x4) //0x40013804
#define LUMMOD_UART_Tx_DMA_Channel DMA1_Channel2
#define LUMMOD_UART_Tx_DMA_FLAG DMA1_FLAG_GL2//DMA1_FLAG_TC2 | DMA1_FLAG_TE2
#define LUMMOD_UART_Tx_DMA_IRQ DMA1_Channel2_IRQn
#define LUMMOD_UART_Rx_DMA_Channel DMA1_Channel3
#define LUMMOD_UART_Rx_DMA_FLAG DMA1_FLAG_GL3//DMA1_FLAG_TC3 | DMA1_FLAG_TE3
#define LUMMOD_UART_Rx_DMA_IRQ DMA1_Channel3_IRQn
void Uart_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* System Clocks Configuration */
//= System Clocks Configuration ====================================================================//
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(LUMMOD_UART_GPIO_CLK , ENABLE ); // 开启串口所在IO端口的时钟
/* Enable USART Clock */
RCC_APB1PeriphClockCmd(LUMMOD_UART_CLK, ENABLE); // 开始串口时钟
//=NVIC_Configuration==============================================================================//
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
/* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = LUMMOD_UART_Tx_DMA_IRQ; // 发送DMA通道的中断配置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 优先级设置
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable the USART Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = LUMMOD_UART_IRQn; // 串口中断配置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//=GPIO_Configuration==============================================================================//
GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE); // 我这里没有用默认IO口,所以进行了重新映射,这个可以根据自己的硬件情况配置选择
/* Configure USART3 Rx as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 串口接收IO口的设置
GPIO_InitStructure.GPIO_Pin = LUMMOD_UART_RxPin;
GPIO_Init(LUMMOD_UART_GPIO, &GPIO_InitStructure);
/* Configure USART3 Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 串口发送IO口的设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 这里设置成复用形式的推挽输出
GPIO_InitStructure.GPIO_Pin = LUMMOD_UART_TxPin;
GPIO_Init(LUMMOD_UART_GPIO, &GPIO_InitStructure);
DMA_Uart_Init(); // 串口 DMA 配置
/* USART Format configuration ------------------------------------------------------*/
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 串口格式配置
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* Configure USART3 */
USART_InitStructure.USART_BaudRate = 115200; // 波特率设置
USART_Init(LUMMOD_UART, &USART_InitStructure);
/* Enable USART3 Receive and Transmit interrupts */
USART_ITConfig(LUMMOD_UART, USART_IT_IDLE, ENABLE); // 开启 串口空闲IDEL 中断
/* Enable the USART3 */
USART_Cmd(LUMMOD_UART, ENABLE); // 开启串口
/* Enable USARTy DMA TX request */
USART_DMACmd(LUMMOD_UART, USART_DMAReq_Tx, ENABLE); // 开启串口DMA发送
USART_DMACmd(LUMMOD_UART, USART_DMAReq_Rx, ENABLE); // 开启串口DMA接收
}
void DMA_Uart_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 开启DMA1时钟
//=DMA_Configuration==============================================================================//
/*--- LUMMOD_UART_Tx_DMA_Channel DMA Config ---*/
DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DISABLE); // 关DMA通道
DMA_DeInit(LUMMOD_UART_Tx_DMA_Channel); // 恢复缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&LUMMOD_UART->DR);// 设置串口发送数据寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LumMod_Tx_Buf; // 设置发送缓冲区首地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 设置外设位目标,内存缓冲区 ->外设寄存器
DMA_InitStructure.DMA_BufferSize = LUMMOD_TX_BSIZE; // 需要发送的字节数,这里其实可以设置为0,因为在实际要发送的时候,会重新设置次值
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不做增加调整,调整不调整是DMA自动实现的
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存缓冲区地址增加调整
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据宽度8位,1个字节
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 单次传输模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // 优先级设置
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 关闭内存到内存的DMA模式
DMA_Init(LUMMOD_UART_Tx_DMA_Channel, &DMA_InitStructure); // 写入配置
DMA_ClearFlag(LUMMOD_UART_Tx_DMA_FLAG); // 清除DMA所有标志
DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DISABLE); // 关闭DMA
DMA_ITConfig(LUMMOD_UART_Tx_DMA_Channel, DMA_IT_TC, ENABLE); // 开启发送DMA通道中断
/*--- LUMMOD_UART_Rx_DMA_Channel DMA Config ---*/
DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, DISABLE); // 关DMA通道
DMA_DeInit(LUMMOD_UART_Rx_DMA_Channel); // 恢复缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&LUMMOD_UART->DR);// 设置串口接收数据寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LumMod_Rx_Buf; // 设置接收缓冲区首地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 设置外设为数据源,外设寄存器 -> 内存缓冲区
DMA_InitStructure.DMA_BufferSize = LUMMOD_RX_BSIZE; // 需要最大可能接收到的字节数
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不做增加调整,调整不调整是DMA自动实现的
上一篇:CAN通信标准帧和扩展帧
下一篇:STM32F105 CAN总线数据收发调试
推荐阅读
史海拾趣
ELESTA一直注重生产效率和产品质量的提升。公司积极引入精益生产理念,通过优化生产流程、提高生产效率、降低生产成本等方式,不断提升产品竞争力和市场占有率。这一举措不仅为公司带来了显著的经济效益,也为整个电子行业树立了标杆。
1997年,ELESTA继电器有限公司正式成立,专注于制造符合IEC 61810-3标准的强制导向触点继电器。这一战略举措进一步巩固了ELESTA在电子继电器领域的领先地位,并为公司的长期发展奠定了坚实的基础。
1970年,Corning Cable Systems公司凭借其创新技术,成功发明了世界上首款低损耗光纤。这一里程碑式的发明彻底改变了通信行业的面貌,推动了光纤通信的飞速发展。此后,公司不断突破技术壁垒,提升光纤性能,为全球范围内的通信网络建设提供了强有力的支持。
在全球半导体市场竞争日益激烈的背景下,芯邦科技面临着来自国际巨头的挑战。然而,公司凭借在半导体设计领域的深厚积累和不断创新的精神,逐步形成了自己的核心竞争力。同时,芯邦也积极寻求与国际合作伙伴的合作机会,共同推动半导体产业的发展。
以上五个故事简要概述了芯邦科技在电子行业中的发展起来的关键节点和里程碑事件。这些故事不仅展现了芯邦科技在技术创新、产品线拓展、资本运作、市场表现和国际竞争等方面的努力和成就,也预示着公司未来发展的广阔前景和无限可能。
近年来,芯邦科技的营收规模逐渐增大,从2020年到2022年,公司的营业收入分别达到了0.99亿元、1.75亿元和1.92亿元。尽管增速呈现下降趋势,但芯邦科技在电子行业中依然保持着稳健的市场表现。同时,公司也注重研发投入,不断提升产品的技术水平和市场适应性。
Fujitsu America作为Fujitsu Limited在北美地区的子公司,其发展历程与Fujitsu全球公司紧密相连。Fujitsu最初成立于1935年,最初是一家电信设备制造商,以生产电话交换机起家。随着技术的不断进步,Fujitsu逐渐扩展到信息与通信技术(ICT)领域,成为全球领先的ICT企业。Fujitsu America在这一过程中发挥了重要作用,不仅继承了Fujitsu在技术创新上的优良传统,还根据北美市场的需求特点,提供了定制化的ICT解决方案和服务,推动了公司在北美市场的快速发展。
最近在学习DSP, 想知道TI公司的TMS320C2812和TMS320F2812的区别是什么,各自的应用在哪个方面。 上周上课时候,我忘记问老师了,刚在网上也没有找到相应的。身边没有这个方面的材料, 所以就只有到咱坛子里面求教各位达人了!! 帮帮忙,谢谢 ...… 查看全部问答∨ |
|
请教有关MC55连接TCP 发送数据的问题: 各位大侠,我在用西门子的MC55做数据传输,现在首先要进行TCP连接,已经可以登陆GPRS网了(因为已经可以获得从网络分配的ip),我测试的步骤如下 at^sics=0,conType,GPRS0 at^sics=0,passwd,gprs at^sics= ...… 查看全部问答∨ |
紧急求助:Realtek RTL8168/811 与DM9000 不能联通 在下使用YLP2410 wince5.0 用交叉网线与PC机端(winxp操作系统)连接后,网卡不能ping通(网卡地址已设为同一段),PC机也提示已连接上,但就是不能ping通,我的IP设置如下: PC端: IP地址:192.168.0.7 ...… 查看全部问答∨ |
同一个进程之间的线程如何通讯 触摸屏驱动,LCD驱动,同为GWES加载,是否可以认为是GWES进程中的多个线程? 同一个进程之间的线程通讯是否和不同进程间的通讯相同? 普通流接口驱动 以DLL形式存在 被同一个进程(device. ...… 查看全部问答∨ |
|
正在食堂吃饭哦,接到电话了,我一猜都是8962来了。。。。没办法,不吃了,冲出去拿板了。。 哈哈。 板子看到和拿到这感觉相差太远了。。。。 新年新给力呀。。。再次感 ...… 查看全部问答∨ |
|