串口
串口TX-DMA功能有何优势?
STM32F103ZE该如何去使用串口TX-DMA功能呢?
回帖(1)
2021-12-14 09:53:09
STM32F103ZE 串口1发送DMA
最近在使用stm32f103ze-144pin做一个案子,记录一下,毕竟网上有些人也在寻找,或许和我遇到的问题相同,供好学者参考,减少时间。以下程序都基于V3.5.0在野火串口TX-DMA例程基础上进行调整改动,以实现能够软件可控DMA-TX
案子需要使用串口TX-DMA功能,使用这个的原因在于:不需要用死循环等待发送完成标志位,程序如下:
(while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);),
我们都知道,死循环会导致mcu在main函数里面占有很大的无用时间,只能通过中断可以介入触发,而现实中,中断也不是无穷多,并且中断触发过多和中断内容过多,会导致打乱main函数程序,因此在我看来,定时中断函数内容尽可能短,触发时间我一般定为100us,时间长短每个人各不相同,可以根据需要设定。
进入正题,设定串口DMA程序,我直接贴下:
1,开RCC-DMA时钟,程序:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2,开NVIC中断,用于在发送一次完成后,DMA触发中断,以此来停止多次循环(DMA_Mode_Circular),程序:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//组0
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; //DMA1通道4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
3,设定DMA相关函数,程序:
#define USART1_DR_Base 0x40013804 //串口1TX寄存器地址
#define SENDBUFF_SIZE 10 //10个byte
uint8_t SendBuff[SENDBUFF_SIZE];//数组存放数据
DMA_DeInit(DMA1_Channel4);//缺省
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; // 串口1寄存器地址
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; //内存数据单位,8bit
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ; //循环发送,此处如果为normal模式,只会发一次,后面不会再发
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,中
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止内存到内存的传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure); // 配置DMA1通道 4
DMA_Cmd (DMA1_Channel4,ENABLE); //使能DMA1通道4
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //DMA发送完后产生中断
对于为什么串口1发送地址是 0x40013804 ,在《stm32f103数据手册》中有提到,截图如下:
然后在《stm32f10xxxxx使用手册》中提到了串口发送寄存器USART-DR的相关偏移地址:
对于选择DMA1通道4的理由在于,32已经规定了DMA1-Channel4是几种外设资源的DMA,而UART1-TX就是其中一种,这一点《stm32f10xxxxx使用手册》也提到了,因此在调用ADC或者是UART2等资源的DMA时候就要注意了。
4,主函数,程序:
main()
{
//初始化;
while(1)
{
//1s定时器标志位,每1s进入一次,使用定时中断,或者delay
{
for(i=0;i<10;i++)//发10个
{
SendBuff = i;
}
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//启动发送DMA请求
}
}
}
以上就是将数据i内容压入SendBuff,就可以让DMA发送啦
5,中断函数,程序:
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET) //判断是否DMA-TX发送完毕
{
USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);//失能TX请求,让DMA不再循环发送,没有这句,会一直不断循环发送
DMA_ClearFlag(DMA1_FLAG_TC4); //清除中断标志位,下次不再进入
}
}
串口相关程序已被我省略,烦请调通串口轮循发送模式后,再看此份文章,谢谢。以上就是我在调试DMA-TX中的设置程序,目前每秒只发送固定10个byte,可通过修改SENDBUFF_SIZE来改变传输数据量。
如有问题,那也没辙。
STM32F103ZE 串口1发送DMA
最近在使用stm32f103ze-144pin做一个案子,记录一下,毕竟网上有些人也在寻找,或许和我遇到的问题相同,供好学者参考,减少时间。以下程序都基于V3.5.0在野火串口TX-DMA例程基础上进行调整改动,以实现能够软件可控DMA-TX
案子需要使用串口TX-DMA功能,使用这个的原因在于:不需要用死循环等待发送完成标志位,程序如下:
(while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);),
我们都知道,死循环会导致mcu在main函数里面占有很大的无用时间,只能通过中断可以介入触发,而现实中,中断也不是无穷多,并且中断触发过多和中断内容过多,会导致打乱main函数程序,因此在我看来,定时中断函数内容尽可能短,触发时间我一般定为100us,时间长短每个人各不相同,可以根据需要设定。
进入正题,设定串口DMA程序,我直接贴下:
1,开RCC-DMA时钟,程序:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2,开NVIC中断,用于在发送一次完成后,DMA触发中断,以此来停止多次循环(DMA_Mode_Circular),程序:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//组0
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; //DMA1通道4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
3,设定DMA相关函数,程序:
#define USART1_DR_Base 0x40013804 //串口1TX寄存器地址
#define SENDBUFF_SIZE 10 //10个byte
uint8_t SendBuff[SENDBUFF_SIZE];//数组存放数据
DMA_DeInit(DMA1_Channel4);//缺省
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; // 串口1寄存器地址
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; //内存数据单位,8bit
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ; //循环发送,此处如果为normal模式,只会发一次,后面不会再发
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,中
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止内存到内存的传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure); // 配置DMA1通道 4
DMA_Cmd (DMA1_Channel4,ENABLE); //使能DMA1通道4
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //DMA发送完后产生中断
对于为什么串口1发送地址是 0x40013804 ,在《stm32f103数据手册》中有提到,截图如下:
然后在《stm32f10xxxxx使用手册》中提到了串口发送寄存器USART-DR的相关偏移地址:
对于选择DMA1通道4的理由在于,32已经规定了DMA1-Channel4是几种外设资源的DMA,而UART1-TX就是其中一种,这一点《stm32f10xxxxx使用手册》也提到了,因此在调用ADC或者是UART2等资源的DMA时候就要注意了。
4,主函数,程序:
main()
{
//初始化;
while(1)
{
//1s定时器标志位,每1s进入一次,使用定时中断,或者delay
{
for(i=0;i<10;i++)//发10个
{
SendBuff = i;
}
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//启动发送DMA请求
}
}
}
以上就是将数据i内容压入SendBuff,就可以让DMA发送啦
5,中断函数,程序:
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET) //判断是否DMA-TX发送完毕
{
USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);//失能TX请求,让DMA不再循环发送,没有这句,会一直不断循环发送
DMA_ClearFlag(DMA1_FLAG_TC4); //清除中断标志位,下次不再进入
}
}
串口相关程序已被我省略,烦请调通串口轮循发送模式后,再看此份文章,谢谢。以上就是我在调试DMA-TX中的设置程序,目前每秒只发送固定10个byte,可通过修改SENDBUFF_SIZE来改变传输数据量。
如有问题,那也没辙。
举报
更多回帖