您的位置 首页 编程

STM32F10x 学习笔记8(USART完成串口通讯 DMA 方法)

STM32F10x的USART支持DMA方式,并且在DMA完成后可以产生中断。这对于需要接收或发送大量数据的应用情景是很有帮助的。在普通的8位或16位单…

STM32F10xUSART支撑DMA方法,并且在DMA完结后能够发生中止。这关于需求接纳或发送很多数据的运用情形是很有协助的。

在一般的8位或16位单片机中很少有包括DMA控制器的,所以或许许多嵌入式程序员对DMA方法并不了解。简略的说,直接存储器存取(DMA)用来供给在外设和存储器之间或许存储器和存储器之间的高速数据传输。咱们无须CPU干涉,数据能够经过DMA快速地移动,这就节省了CPU的资源来做其他操作。

STM32F10x上具有两个DMA控制器,共有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来办理来自于一个或多个外设对存储器拜访的恳求。还有一个裁定器来和谐各个DMA恳求的优先权。

依照STM32参考手册上的说法:“DMA控制器和Cortex™-M3中心同享体系数据总线,碑文直接存储器数据传输。当CPU和DMA一起拜访相同的方针(RAM或外设)时,DMA恳求会暂停CPU拜访体系总线达若干个周期,总线裁定器碑文循环调度,以确保CPU至少能够得到一半的体系总线(存储器或外设)带宽。”所以咱们不用忧虑DMA控制器强占总线资源。CPU总是能够得到一般的总线时刻的。

下面咱们以USART2的数据发送为例来介绍DMA。首要由STM32参考手册的图22可知。USART2的发送功用能够运用DMA1的第7个通道。

运用的DMA传输的设置作业大体能够分为6步:

1.在DMA1_CPAR7寄存器中设置外设寄存器的地址。发生外设数据传输恳求时,这个地址将是数据传输的源或方针。

2.在DMA1_CMAR7寄存器中设置数据存储器的地址。发生外设数据传输恳求时,传输的数据将从这个地址读出或写入这个地址。

3.在DMA1_CNDTR7寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。

4.在DMA1_CCR7寄存器的PL[1:0]位中设置通道的优先级。

5.在DMA1_CCR7寄存器中设置数据传输的方向、循环形式、外设和存储器的增量形式、外设和存储器的数据宽度、传输一半发生中止或传输完结发生中止。

6.设置DMA1_CCR7寄存器的ENABLE位,发动该通道。

第1步对应的代码为:

  1. DMA1_Channel7->CPAR=(uint32_t)&(USART2->DR);

第2步对应的代码如下,其间p_str是一个指针,指向要传输的数据的首地址:

  1. DMA1_Channel7->CMAR=(uint32_t)p_str;

第3步对应的代码如下,cnt为要传输的数据量,串口数据是以字节为传输单位的,所以这儿cnt便是要传输数据的字节数。

  1. DMA1_Channel7->CNDTR=cnt;

第4步对应的代码如下,DMA通道的优先级分为4级,分别是:DMA_Priority_VeryHigh、DMA_Priority_High、DMA_Priority_Medium、DMA_Priority_Low。这儿设为最低。

  1. DMA1_Channel7->CCR|=DMA_Priority_Low;

第5步对应的代码如下:

  1. DMA1_Channel7->CCR|=DMA_DIR_PeripheralDST|
  2. DMA_Mode_Normal|
  3. DMA_PeripheralInc_Disable|
  4. DMA_MemoryInc_Enable|
  5. DMA_PeripheralDataSize_Byte|
  6. DMA_MemoryDataSize_Byte|
  7. DMA_M2M_Disable;

第6步对应的代码如下:

  1. DMA1_Channel7->CCR|=DMA_CCR1_EN;

实际上在这6步之前应该还有2步操作。首要设置DMA之前,要翻开DMA的时钟:

  1. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

其次,也要设置USART使其支撑DMA方法:

  1. USARTx->CR3|=USART_DMAReq_Tx;

或许用下面的函数:

  1. USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);

一旦发动了DMA通道,它既可呼应连到该通道上的外设的DMA恳求。完结一次DMA传输后怎么舱位下一次传输呢,这个问题困扰了我好几天,最终在STM32参考手册上发现如下的一句话:

当通道装备为非循环形式时,传输完毕后(即传输计数变为0)将不再发生DMA操作。要开端新的DMA传输,需求在封闭DMA通道的情况下,在DMA_CNDTRx寄存器中从头写入传输数目。

下面先给一个简略的示例程序:

  1. voidUSART2_Init(void)
  2. {
  3. GPIO_InitTypeDefGPIO_InitStructure;
  4. USART_InitTypeDefUSART_InitStructure;
  5. NVIC_InitTypeDefNVIC_InitStructure;
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO,ENABLE);
  7. /*ConfigureUSARTTxasalternatefunctionpush-pull*/
  8. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  9. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
  10. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  11. GPIO_Init(GPIOD,&GPIO_InitStructure);
  12. /*ConfigureUSARTRxasinputfloating*/
  13. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  14. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
  15. GPIO_Init(GPIOD,&GPIO_InitStructure);
  16. GPIO_PinRemapConfig(GPIO_Remap_USART2,ENABLE);
  17. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
  18. USART_InitStructure.USART_BaudRate=9600;
  19. USART_InitStructure.USART_WordLength=USART_WordLength_8b;
  20. USART_InitStructure.USART_StopBits=USART_StopBits_1;
  21. USART_InitStructure.USART_Parity=USART_Parity_No;
  22. USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  23. USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
  24. USART_Init(USART2,&USART_InitStructure);
  25. USART_Cmd(USART2,ENABLE);
  26. }
  27. voidUART2_TX_DMA_Init(uint8_t*p_str,uint16_tcnt)
  28. {
  29. //DMA_InitTypeDefDMA_InitStructure;
  30. //DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(USART2->DR);
  31. //DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)str;
  32. //DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
  33. //DMA_InitStructure.DMA_BufferSize=14;
  34. //DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  35. //DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
  36. //DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
  37. //DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
  38. //DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
  39. //DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
  40. //DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
  41. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
  42. //DMA_Init(DMA1_Channel7,&DMA_InitStructure);
  43. DMA1_Channel7->CPAR=(uint32_t)&(USART2->DR);
  44. DMA1_Channel7->CMAR=(uint32_t)p_str;
  45. DMA1_Channel7->CNDTR=cnt;
  46. DMA1_Channel7->CCR=DMA_DIR_PeripheralDST|DMA_Priority_Low|
  47. DMA_Mode_Normal|DMA_PeripheralInc_Disable|
  48. DMA_MemoryInc_Enable|DMA_PeripheralDataSize_Byte|
  49. DMA_MemoryDataSize_Byte|DMA_M2M_Disable;
  50. }
  51. uint8_tstr[]=”HelloWorld!!!”;
  52. voidTaskStart(void*pdata)
  53. {
  54. SysTick_Config(SystemCoreClock/10);
  55. USART2_Init();
  56. UART2_TX_DMA_Init(str,14);
  57. for(;;)
  58. {
  59. LED_Spark();
  60. //DMA_Cmd(DMA1_Channel7,DISABLE);
  61. DMA1_Channel7->CCR&=(uint16_t)(~DMA_CCR1_EN);
  62. //DMA_Init(DMA1_Channel7,&DMA_InitStructure);
  63. DMA1_Channel7->CNDTR=14;
  64. //DMA_Cmd(DMA1_Channel7,ENABLE);
  65. DMA1_Channel7->CCR|=DMA_CCR1_EN;
  66. //USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);
  67. OSTimeDly(10);
  68. }
  69. }
  70. intmain(void)
  71. {
  72. SystemInit();
  73. LED_Init();
  74. OSInit();
  75. OSTaskCreate(TaskStart,(void*)0,&(TaskStartStk[TASK_STK_SIZE-1]),1);
  76. OSStart();
  77. for(;;)
  78. {
  79. }
  80. }

下面再说说怎么在DMA传输完结之后发生中止。当传输一半的数据后,半传输标志(HTIF)被置1,当设置了答应半传输中止位(HTIE)时,将发生一个中止恳求。在数据传输完毕后,传输完结标志(TCIF)被置1,当设置了答应传输完结中止位(TCIE)时,将发生一个中止恳求。

DMA的CCR寄存器中有1位TCIE(Transfercompleteinterruptenable)

该位由软件设置和铲除。

0:制止TC中止

1:答应TC中止

所以为了运用DMA中止,咱们需求下面的代码:

  1. DMA1_Channel7->CCR|=DMA_IT_TC;//Transfercompleteinterruptenable
  1. NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel7_IRQn;
  2. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=5;
  3. NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
  4. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  5. NVIC_Init(&NVIC_InitStructure);

下面仍是给个简略的示例程序,示例程序中还用到了uCOS的信号量,中止处理函数经过信号量告诉Task完结了DMA传输:

  1. #include”stm32f10x.h”
  2. #include”uart.h”
  3. #include”led.h”
  4. #include”COMMRTOS.H”
  5. #include”ucos_ii.h”
  6. #defineTASK_STK_SIZE128
  7. OS_STKTaskStartStk[TASK_STK_SIZE];
  8. voidUSART2_Init(void)
  9. {
  10. GPIO_InitTypeDefGPIO_InitStructure;
  11. USART_InitTypeDefUSART_InitStructure;
  12. NVIC_InitTypeDefNVIC_InitStructure;
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO,ENABLE);
  14. /*ConfigureUSARTTxasalternatefunctionpush-pull*/
  15. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  16. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
  17. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  18. GPIO_Init(GPIOD,&GPIO_InitStructure);
  19. /*ConfigureUSARTRxasinputfloating*/
  20. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  21. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
  22. GPIO_Init(GPIOD,&GPIO_InitStructure);
  23. GPIO_PinRemapConfig(GPIO_Remap_USART2,ENABLE);
  24. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
  25. USART_InitStructure.USART_BaudRate=9600;
  26. USART_InitStructure.USART_WordLength=USART_WordLength_8b;
  27. USART_InitStructure.USART_StopBits=USART_StopBits_1;
  28. USART_InitStructure.USART_Parity=USART_Parity_No;
  29. USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  30. USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
  31. USART_Init(USART2,&USART_InitStructure);
  32. USART_Cmd(USART2,ENABLE);
  33. NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
  34. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
  35. NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
  36. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  37. NVIC_Init(&NVIC_InitStructure);
  38. }
  39. voidUART2_TX_DMA_Init(uint8_t*p_str,uint16_tcnt)
  40. {
  41. //DMA_InitTypeDefDMA_InitStructure;
  42. //DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(USART2->DR);
  43. //DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)str;
  44. //DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
  45. //DMA_InitStructure.DMA_BufferSize=14;
  46. //DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  47. //DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
  48. //DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
  49. //DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
  50. //DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
  51. //DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
  52. //DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
  53. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
  54. //DMA_Init(DMA1_Channel7,&DMA_InitStructure);
  55. DMA1_Channel7->CPAR=(uint32_t)&(USART2->DR);
  56. DMA1_Channel7->CMAR=(uint32_t)p_str;
  57. DMA1_Channel7->CNDTR=cnt;
  58. DMA1_Channel7->CCR=DMA_DIR_PeripheralDST|DMA_Priority_Low|
  59. DMA_Mode_Normal|DMA_PeripheralInc_Disable|
  60. DMA_MemoryInc_Enable|DMA_PeripheralDataSize_Byte|
  61. DMA_MemoryDataSize_Byte|DMA_M2M_Disable;
  62. }
  63. OS_EVENT*UART2_DMA_TX_Sem;
  64. uint8_tstr[]=”HelloWorld!!!”;
  65. voidTaskStart(void*pdata)
  66. {
  67. unsignedcharerr;
  68. SysTick_Config(SystemCoreClock/10);
  69. USART2_Init();
  70. USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);
  71. UART2_TX_DMA_Init(str);
  72. UART2_DMA_TX_Sem=OSSemCreate(1);
  73. for(;;)
  74. {
  75. LED_Spark();
  76. OSSemPend(UART2_DMA_TX_Sem,0,&err);
  77. //DMA_Cmd(DMA1_Channel7,DISABLE);
  78. DMA1_Channel7->CCR&=(uint16_t)(~DMA_CCR1_EN);
  79. //DMA_Init(DMA1_Channel7,&DMA_InitStructure);
  80. DMA1_Channel7->CNDTR=14;
  81. //DMA_Cmd(DMA1_Channel7,ENABLE);
  82. DMA1_Channel7->CCR|=DMA_CCR1_EN;
  83. //USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);
  84. OSTimeDly(10);
  85. }
  86. }
  87. intmain(void)
  88. {
  89. SystemInit();
  90. LED_Init();
  91. OSInit();
  92. OSTaskCreate(TaskStart,(void*)0,&(TaskStartStk[TASK_STK_SIZE-1]),1);
  93. OSStart();
  94. for(;;)
  95. {
  96. }
  97. }
  98. voidDMA1_Channel7_IRQHandler(void)
  99. {
  100. OS_CPU_SRcpu_sr;
  101. OS_ENTER_CRITICAL();/*TelluC/OS-IIthatwearestartinganISR*/
  102. OSIntNesting++;
  103. OS_EXIT_CRIT%&&&&&%AL();
  104. OSSemPost(UART2_DMA_TX_Sem);
  105. //UART_PutChar(USART2,+);
  106. DMA1->IFCR=DMA1_FLAG_TC7;
  107. OSIntExit();
  108. }

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/biancheng/264249.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部