<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > STM32F10x 學(xué)習(xí)筆記8(USART實(shí)現(xiàn)串口通訊 DMA 方式)

          STM32F10x 學(xué)習(xí)筆記8(USART實(shí)現(xiàn)串口通訊 DMA 方式)

          作者: 時(shí)間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
          STM32F10xUSART支持DMA方式,并且在DMA完成后可以產(chǎn)生中斷。這對(duì)于需要接收或發(fā)送大量數(shù)據(jù)的應(yīng)用情景是很有幫助的。

          本文引用地址:http://www.ex-cimer.com/article/201611/318844.htm

          在普通的8位或16位單片機(jī)中很少有包含DMA控制器的,所以可能許多嵌入式程序員對(duì)DMA方式并不熟悉。簡單的說,直接存儲(chǔ)器存取(DMA)用來提供在外設(shè)和存儲(chǔ)器之間或者存儲(chǔ)器和存儲(chǔ)器之間的高速數(shù)據(jù)傳輸。由于無須CPU干預(yù),數(shù)據(jù)可以通過DMA快速地移動(dòng),這就節(jié)省了CPU的資源來做其他操作。

          STM32F10x上具有兩個(gè)DMA控制器,共有12個(gè)通道(DMA1有7個(gè)通道,DMA2有5個(gè)通道),每個(gè)通道專門用來管理來自于一個(gè)或多個(gè)外設(shè)對(duì)存儲(chǔ)器訪問的請(qǐng)求。還有一個(gè)仲裁器來協(xié)調(diào)各個(gè)DMA請(qǐng)求的優(yōu)先權(quán)。

          按照STM32參考手冊(cè)上的說法:“DMA控制器和Cortex™-M3核心共享系統(tǒng)數(shù)據(jù)總線,執(zhí)行直接存儲(chǔ)器數(shù)據(jù)傳輸。當(dāng)CPU和DMA同時(shí)訪問相同的目標(biāo)(RAM或外設(shè))時(shí),DMA請(qǐng)求會(huì)暫停CPU訪問系統(tǒng)總線達(dá)若干個(gè)周期,總線仲裁器執(zhí)行循環(huán)調(diào)度,以保證CPU至少可以得到一半的系統(tǒng)總線(存儲(chǔ)器或外設(shè))帶寬。”所以我們不必?fù)?dān)心DMA控制器霸占總線資源。CPU總是可以得到一般的總線時(shí)間的。

          下面我們以USART2的數(shù)據(jù)發(fā)送為例來介紹DMA。首先由STM32參考手冊(cè)的圖22可知。USART2的發(fā)送功能可以使用DMA1的第7個(gè)通道。

          利用的DMA傳輸?shù)脑O(shè)置工作大體可以分為6步:

          1.在DMA1_CPAR7寄存器中設(shè)置外設(shè)寄存器的地址。發(fā)生外設(shè)數(shù)據(jù)傳輸請(qǐng)求時(shí),這個(gè)地址將是數(shù)據(jù)傳輸?shù)脑椿蚰繕?biāo)。

          2.在DMA1_CMAR7寄存器中設(shè)置數(shù)據(jù)存儲(chǔ)器的地址。發(fā)生外設(shè)數(shù)據(jù)傳輸請(qǐng)求時(shí),傳輸?shù)臄?shù)據(jù)將從這個(gè)地址讀出或?qū)懭脒@個(gè)地址。

          3.在DMA1_CNDTR7寄存器中設(shè)置要傳輸?shù)臄?shù)據(jù)量。在每個(gè)數(shù)據(jù)傳輸后,這個(gè)數(shù)值遞減。

          4.在DMA1_CCR7寄存器的PL[1:0]位中設(shè)置通道的優(yōu)先級(jí)。

          5.在DMA1_CCR7寄存器中設(shè)置數(shù)據(jù)傳輸?shù)姆较?、循環(huán)模式、外設(shè)和存儲(chǔ)器的增量模式、外設(shè)和存儲(chǔ)器的數(shù)據(jù)寬度、傳輸一半產(chǎn)生中斷或傳輸完成產(chǎn)生中斷。

          6.設(shè)置DMA1_CCR7寄存器的ENABLE位,啟動(dòng)該通道。

          第1步對(duì)應(yīng)的代碼為:

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

          第2步對(duì)應(yīng)的代碼如下,其中p_str是一個(gè)指針,指向要傳輸?shù)臄?shù)據(jù)的首地址:

          1. DMA1_Channel7->CMAR=(uint32_t)p_str;
          第3步對(duì)應(yīng)的代碼如下,cnt為要傳輸?shù)臄?shù)據(jù)量,串口數(shù)據(jù)是以字節(jié)為傳輸單位的,所以這里cnt就是要傳輸數(shù)據(jù)的字節(jié)數(shù)。

          1. DMA1_Channel7->CNDTR=cnt;
          第4步對(duì)應(yīng)的代碼如下,DMA通道的優(yōu)先級(jí)分為4級(jí),分別是:DMA_Priority_VeryHigh、DMA_Priority_High、DMA_Priority_Medium、DMA_Priority_Low。這里設(shè)為最低。

          1. DMA1_Channel7->CCR|=DMA_Priority_Low;
          第5步對(duì)應(yīng)的代碼如下:

          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步對(duì)應(yīng)的代碼如下:

          1. DMA1_Channel7->CCR|=DMA_CCR1_EN;

          實(shí)際上在這6步之前應(yīng)該還有2步操作。首先設(shè)置DMA之前,要打開DMA的時(shí)鐘:

          1. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
          其次,也要設(shè)置USART使其支持DMA方式:
          1. USARTx->CR3|=USART_DMAReq_Tx;

          或者用下面的函數(shù):


          1. USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);

          一旦啟動(dòng)了DMA通道,它既可響應(yīng)連到該通道上的外設(shè)的DMA請(qǐng)求。完成一次DMA傳輸后如何開啟下一次傳輸呢,這個(gè)問題困擾了我好幾天,最后在STM32參考手冊(cè)上發(fā)現(xiàn)如下的一句話:

          當(dāng)通道配置為非循環(huán)模式時(shí),傳輸結(jié)束后(即傳輸計(jì)數(shù)變?yōu)?)將不再產(chǎn)生DMA操作。要開始新的DMA傳輸,需要在關(guān)閉DMA通道的情況下,在DMA_CNDTRx寄存器中重新寫入傳輸數(shù)目。

          下面先給一個(gè)簡單的示例程序:

          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傳輸完成之后產(chǎn)生中斷。當(dāng)傳輸一半的數(shù)據(jù)后,半傳輸標(biāo)志(HTIF)被置1,當(dāng)設(shè)置了允許半傳輸中斷位(HTIE)時(shí),將產(chǎn)生一個(gè)中斷請(qǐng)求。在數(shù)據(jù)傳輸結(jié)束后,傳輸完成標(biāo)志(TCIF)被置1,當(dāng)設(shè)置了允許傳輸完成中斷位(TCIE)時(shí),將產(chǎn)生一個(gè)中斷請(qǐng)求。

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

          該位由軟件設(shè)置和清除。

          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);

          下面還是給個(gè)簡單的示例程序,示例程序中還用到了uCOS的信號(hào)量,中斷處理函數(shù)通過信號(hào)量通知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_CRITICAL();
          104. OSSemPost(UART2_DMA_TX_Sem);
          105. //UART_PutChar(USART2,+);
          106. DMA1->IFCR=DMA1_FLAG_TC7;
          107. OSIntExit();
          108. }



          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();