串口以DMA方式发送(TX)数据

  实验:控制串口一以DMA方式发送(TX)数据

 

一、初始化DMA

       对STM32任何模块使用前都要对其初始化、首先就是初始化外设时钟,查看时钟

数可知DMA时钟由AHB得来。

初始化时钟:RCC->AHBENR|=1<<0;

        在读数据手册可知:直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。 两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。我们实验用的是串口一、查看外设与通道的对应关系如下:

所以我们初始化DMA1的第四通道。关于通道配置过程:

其中几个简单个人理解:

CPARx:就是串口发送数据的寄存器地址;

CMARx:就是DMA传输的数据的地址;

CMDTRx:就是传输的数据大小 ,按字节传输,传输后值递减;

  1. <span style="background-color: rgb(240, 240, 240);">void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)</span>{  
  2.     RCC->AHBENR|=1<<0;         //开启DMA1时钟  
  3.     delay_ms(5);                //等待DMA时钟稳定  
  4.     DMA_CHx->CPAR=cpar;      //DMA1 外设地址   
  5.     DMA_CHx->CMAR=(u32)cmar;     //DMA1,存储器地址  
  6.     DMA1_MEM_LEN=cndtr;         //保存DMA传输数据量  
  7.     DMA_CHx->CNDTR=cndtr;        //DMA1,传输数据量  
  8.     DMA_CHx->CCR=0X00000000; //复位  
  9.     DMA_CHx->CCR|=1<<4;        //从存储器读  
  10.     DMA_CHx->CCR|=0<<5;        //普通模式  
  11.     DMA_CHx->CCR|=0<<6;        //外设地址非增量模式  
  12.     DMA_CHx->CCR|=1<<7;        //存储器增量模式  
  13.     DMA_CHx->CCR|=0<<8;        //外设数据宽度为8位  
  14.     DMA_CHx->CCR|=0<<10;       //存储器数据宽度8位  
  15.     DMA_CHx->CCR|=1<<12;       //中等优先级  
  16.     DMA_CHx->CCR|=0<<14;       //非存储器到存储器模式              
  17. }  
<span style="background-color: rgb(240, 240, 240);">void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)</span>{
	RCC->AHBENR|=1<<0;			//开启DMA1时钟
	delay_ms(5);				//等待DMA时钟稳定
	DMA_CHx->CPAR=cpar; 	 	//DMA1 外设地址 
	DMA_CHx->CMAR=(u32)cmar; 	//DMA1,存储器地址
	DMA1_MEM_LEN=cndtr;      	//保存DMA传输数据量
	DMA_CHx->CNDTR=cndtr;    	//DMA1,传输数据量
	DMA_CHx->CCR=0X00000000;	//复位
	DMA_CHx->CCR|=1<<4;  		//从存储器读
	DMA_CHx->CCR|=0<<5;  		//普通模式
	DMA_CHx->CCR|=0<<6; 		//外设地址非增量模式
	DMA_CHx->CCR|=1<<7; 	 	//存储器增量模式
	DMA_CHx->CCR|=0<<8; 	 	//外设数据宽度为8位
	DMA_CHx->CCR|=0<<10; 		//存储器数据宽度8位
	DMA_CHx->CCR|=1<<12; 		//中等优先级
	DMA_CHx->CCR|=0<<14; 		//非存储器到存储器模式		  	
}
  1. //开启一次DMA传输  
  2. void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)  
  3. {  
  4.     DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输   
  5.     DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量   
  6.     DMA_CHx->CCR|=1<<0;          //开启DMA传输  
  7. }  
//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
	DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输 
	DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量 
	DMA_CHx->CCR|=1<<0;          //开启DMA传输
}

初始化就基本完成。


在上面标识红色字体可知,开始DMA传输必须要有外设请求:



那么问题来了,请求信号是什么样的呢?


我们查看数据手册串口找到如下内容:




请求信号:就是配置USART_CR3,在实验中配置USART1->CR3=1<<7;


主函数如下:

  1. #define SEND_BUF_SIZE 1200  
  2.   
  3. u8 SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区  
  4. const u8 TEXT_TO_SEND[]={"STM32F1 DMA 串口实验"};      
  5.   
  6. int main(void)  
  7. {     
  8.     u16 i;  
  9.     u8 t=0;  
  10.     u8 j,mask=0;  
  11.     Stm32_Clock_Init(9);    //系统时钟设置  
  12.     uart_init(72,115200);   //串口初始化为115200  
  13.     delay_init(72);         //延时初始化   
  14.     KEY_Init();             //按键初始化           
  15.     MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA1通道4,外设为串口1,存储器为SendBuff,长度SEND_BUF_SIZE.  
  16.     j=sizeof(TEXT_TO_SEND);      
  17.     for(i=0;i<SEND_BUF_SIZE;i++)//填充数据到SendBuff  
  18.     {  
  19.         if(t>=j)//加入换行符  
  20.         {  
  21.             if(mask)  
  22.             {  
  23.                 SendBuff[i]=0x0a;  
  24.                 t=0;  
  25.             }else   
  26.             {  
  27.                 SendBuff[i]=0x0d;  
  28.                 mask++;  
  29.             }     
  30.         }else//复制TEXT_TO_SEND语句  
  31.         {  
  32.             mask=0;  
  33.             SendBuff[i]=TEXT_TO_SEND[t];  
  34.             t++;  
  35.         }            
  36.     }          
  37.     i=0;  
  38.     while(1)  
  39.     {  
  40.         t=KEY_Scan(0);  
  41.         if(t==KEY0_PRES)//KEY0按下  
  42.         {  
  43.             USART1->CR3=1<<7;           //使能串口1的DMA发送         
  44.             MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!        
  45.             //等待DMA传输完成,此时我们来做另外一些事,点灯  
  46.             //实际应用中,传输数据期间,可以执行另外的任务  
  47.             while(1)  
  48.             {  
  49.             <span style="color:#ff0000;"if(DMA1->ISR&(1<<13))//等待通道4传输完成  
  50.                 {  
  51.                     DMA1->IFCR|=1<<13;//清除通道4传输完成标志  
  52.                     break;</span>   
  53.              }  
  54.   
  55.         }  
  56.   }  
  57. }  
  58. }  
#define SEND_BUF_SIZE 1200

u8 SendBuff[SEND_BUF_SIZE];	//发送数据缓冲区
const u8 TEXT_TO_SEND[]={"STM32F1 DMA 串口实验"};	 

int main(void)
{	
	u16 i;
	u8 t=0;
	u8 j,mask=0;
 	Stm32_Clock_Init(9);	//系统时钟设置
	uart_init(72,115200);	//串口初始化为115200
	delay_init(72);	   	 	//延时初始化 
	KEY_Init();				//按键初始化		 	
 	MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA1通道4,外设为串口1,存储器为SendBuff,长度SEND_BUF_SIZE.
	j=sizeof(TEXT_TO_SEND);	   
	for(i=0;i<SEND_BUF_SIZE;i++)//填充数据到SendBuff
    {
		if(t>=j)//加入换行符
		{
			if(mask)
			{
				SendBuff[i]=0x0a;
				t=0;
			}else 
			{
				SendBuff[i]=0x0d;
				mask++;
			}	
		}else//复制TEXT_TO_SEND语句
		{
			mask=0;
			SendBuff[i]=TEXT_TO_SEND[t];
			t++;
		}    	   
    }		 
	i=0;
	while(1)
	{
		t=KEY_Scan(0);
		if(t==KEY0_PRES)//KEY0按下
		{
		    USART1->CR3=1<<7;           //使能串口1的DMA发送       
			MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!	  
		    //等待DMA传输完成,此时我们来做另外一些事,点灯
		    //实际应用中,传输数据期间,可以执行另外的任务
		    while(1)
		    {
			<span style="color:#ff0000;">	if(DMA1->ISR&(1<<13))//等待通道4传输完成
				{
					DMA1->IFCR|=1<<13;//清除通道4传输完成标志
					break;</span> 
		     }

		}
  }
}
}
 

如程序红色部分 传输过程出现错误或者传送完成我们可以设置标志位来提示:


这些标志位都在中断寄存器中:

我们用的是第四通道,所以是13位完成标志位,完成后再清掉中断可以接受下一次中断,清中断寄存器DMA_IFCR与ISR的位对应,这里就不解释了

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的问题是如何利用串口采用DMA方式发送数据到主存,并统计发送数据中包含的字符数。 首先,您需要使用STM32的DMA功能来实现串口数据的传输。具体地,您可以通过配置USART的DMA发送模式,将USART的数据发送寄存器直接映射到DMA的通道中,这样就可以实现DMA发送数据了。 其次,您需要在DMA传输完成中断处理函数中统计发送数据中包含的字符数。具体地,您可以在传输完成中断处理函数中读取DMA传输的字节数,并遍历DMA传输的数据缓冲区,统计其中的字符数。 下面是一个基本的实现思路: 1. 配置USART的DMA发送模式,将USART的数据发送寄存器直接映射到DMA的通道中。 2. 配置DMA传输模式和数据缓冲区,启动DMA传输。 3. 等待DMA传输完成中断。 4. 在DMA传输完成中断处理函数中,读取DMA传输的字节数,并遍历DMA传输的数据缓冲区,统计其中的字符数。 下面是一个示例代码,供您参考: ```c #include "stm32f4xx.h" #define BUFFER_SIZE 100 uint8_t buffer[BUFFER_SIZE]; uint32_t char_count = 0; void DMA2_Stream7_IRQHandler(void) { if (DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7)) { DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); uint32_t byte_count = BUFFER_SIZE - DMA_GetCurrDataCounter(DMA2_Stream7); for (int i = 0; i < byte_count; i++) { if (buffer[i] >= ' ' && buffer[i] <= '~') { char_count++; } } } } int main(void) { // 初始化USART和DMA USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx; USART_Init(USART1, &USART_InitStruct); DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_Channel = DMA_Channel_4; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)buffer; DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream7, &DMA_InitStruct); // 使能USART和DMA USART_Cmd(USART1, ENABLE); DMA_Cmd(DMA2_Stream7, ENABLE); // 等待DMA传输完成中断 while (1); return 0; } ``` 以上是一个基本的实现思路,您可以根据具体的需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值