实现功能:STM32每间隔1秒,串口采用DMA方式发送一帧数据。
硬件:STM32F103、485通讯接口
我的构思:开启定时器定时1秒,计数器溢出触发DMA,而后DMA发送一帧数据,DMA发送完成产生发送完成中断,重新配置DMA再次。
问题:我写完之后采用串口调试助手调试,结果发现数据是1秒一个字节发送出去的,而非一秒一帧发送出去的,然后等数据全部发送完之后进入的DMA中断服务函数。看了许久不知道有什么毛病。求各路大神帮助,不胜感激。以下是相关外设配置程序。
- maim.c:
- int main(void)
- {
- uint16_t i;
- /*填充将要发送的数据*/
- for(i=0;i<SENDBUFF_SIZE;i++)
- {
- SendBuff[i] = 'P';
- if(i == SENDBUFF_SIZE-1)
- SendBuff[i] = 'Q';
- }
-
- LED_GPIO_Config();
- /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
- USART3_Config(); //串口配置
- /* 发送使能 */
- USART3_DMA_Config();//DMA配置
- RS485_TX_EN();//485发送使能
- BASIC_TIM_Init();//定时器配置
- TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);//定时器发送DMA请求
- while(1)
- {
- }
- }
复制代码
- DMA与串口的配置:
- void USART3_DMA_Config(void)
- {
- DMA_InitTypeDef DMA_InitStructure;
-
- // 开启DMA时钟
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- /* 复位初始化 DMA 数据流 */
- DMA_DeInit(DMA1_Channel2);
- // 设置DMA外设地址:串口数据寄存器地址*/
- DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
- // 内存地址(要传输的变量的指针)
- DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
- // 方向:从内存到外设
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- // 传输大小
- DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
- // 外设地址不增
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- // 内存地址自增
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- // 外设数据单位
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- // 内存数据单位
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- // DMA模式,一次或者循环模式
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
- //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
- // 优先级:中
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
- // 禁止内存到内存的传输
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- // 配置DMA通道
- DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
-
- DMA_SetCurrDataCounter(DMA1_Channel2, SENDBUFF_SIZE);
- NVIC_DMA1_2_Configuration();
- //开启DMA通道的TC中断:传输完成中断
- DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
- // 使能DMA
- DMA_Cmd (DMA1_Channel2,ENABLE);
- }
- void DMA1_Ch2_IRQ(void)//DMA中断服务函数
- {
- if(DMA_GetITStatus(DMA1_IT_TC2))
- {
- DMA_ClearITPendingBit(DMA1_IT_GL2); //清除全部中断标志 //DMA_ClearFLAG(DMA1_FLAG_TC2); //清除全部中断标志(这种写法也可以)
- // RS485_RX_EN();
- // 使能串口接收中断
- // USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
- // // 使能串口空闲中断(用于检测一帧数据接收完毕)
- // USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
- }
- // //清TC标志
- // DMA_ClearFlag(DMA1_FLAG_TC4);
- //关闭DMA通道
- // DMA_Cmd(DMA1_Channel2, DISABLE);
- USART3_DMA_Config();
- // RS485_TX_EN();
- }
复制代码- 定时器的配置:
- static void BASIC_TIM_Mode_Config(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
-
- // 开启定时器时钟,即内部时钟CK_INT=72M
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
-
- // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
- TIM_TimeBaseStructure.TIM_Period = 9000-1;
- // 时钟预分频数为71,则驱动计数器的时钟 为CLK/(71+1)=1M
- TIM_TimeBaseStructure.TIM_Prescaler= 8000-1;
-
- // 时钟分频因子 ,基本定时器没有,不用管
- //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
-
- // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
- //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
-
- // 重复计数器的值,基本定时器没有,不用管
- //TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
-
- // 初始化定时器
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
-
- // 清除计数器中断标志位
- TIM_ClearFlag(TIM2, TIM_FLAG_Update);
-
- // // 开启计数器中断
- // TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
-
- //UDE:更新DMA请求使能 (Update DMA request enable) */
- // TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);//定时器发送DMA请求
- // 使能计数器
- TIM_Cmd(TIM2, ENABLE);
- }
- void BASIC_TIM_Init(void)
- {
- BASIC_TIM_NVIC_Config();
- BASIC_TIM_Mode_Config();
- }
复制代码
|
评分
查看全部评分
DMA发送比较快 所以我想用DMA发送
配置有什么问题 这个程序它可以的DMA发送数据 但是没有实现一次一帧而是一次一个字节
DMA发送是硬件发送不占用CPU时间,和你直接发送时间是一样的,
是的 这也是我选择DMA的原因之一 不占用CPU CPU还要干其他的事儿
评分
查看全部评分
评分
查看全部评分
是的我测试过 发现DMA传输完成中断是我定义的数据一字节一字节的全部发送完毕之后才进入的 主要是我觉得很奇怪 之前我用串口发送DMA请求的时候 DMA是一次发送一帧的 而用TIM却成了一次一字节 我想要是实现的也是一次发送全部的数据。。。。。。然后在DMA传输完成中断里面刷新DMA配置