STM32/STM8技术论坛
直播中

贾埃罗

7年用户 1676经验值
私信 关注
[问答]

STM32F103 实现usart1和 ADC1的DMA接收时遇到的问题

这两天在调试程序,需要同时实现usart1串口接收和ADC1数据接收功能。均使用DMA实现。现在是我单独调试usart1的串口接收和ADC接收的时候,都可以工作。放在一起就无法正常工作了。我建立了一个认为,持续接收和打印ADC的数据。然后,我发送串口数据。程序应该就挂掉了。无法再接收串口数据,也无法再接收ADC数据了。所以想请大神指导下,到底是哪里出了问题。是管脚复用?还是配置问题?
下面是我的代码:
  1. uint8_t ReceiveBuff[RECEIVEBUFF_SIZE] = {0};

  2. /**
  3.    * @Brief  USART GPIO 配置,工作参数配置
  4.   * @param  无
  5.   * @retval 无
  6.   */
  7. void USART_Config(void)
  8. {
  9.         GPIO_InitTypeDef GPIO_InitStructure;
  10.         USART_InitTypeDef USART_InitStructure;

  11.         // 打开串口GPIO的时钟
  12. DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);

  13.         // 打开串口外设的时钟
  14. DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

  15.         // 将USART Tx的GPIO配置为推挽复用模式
  16. GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  18.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  19.         GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);

  20.    // 将USART Rx的GPIO配置为浮空输入模式
  21. GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
  22.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOAtiNG;
  23.         GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);

  24.         // 配置串口的工作参数
  25. // 配置波特率
  26. USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  27.         // 配置 针数据字长
  28. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  29.         // 配置停止位
  30. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  31.         // 配置校验位
  32. USART_InitStructure.USART_Parity = USART_Parity_No ;
  33.         // 配置硬件流控制
  34. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  35.         // 配置工作模式,收发一起
  36. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  37.         // 完成串口的初始化配置
  38. USART_Init(DEBUG_USARTx, &USART_InitStructure);        
  39.         //开启空闲中断
  40. USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);

  41.         /* 使能USART1 DMA接收 */
  42. USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Rx, ENABLE);
  43.         // 使能串口
  44. USART_Cmd(DEBUG_USARTx, ENABLE);            
  45. }

  46. /**
  47.    * @brief  USARTx RX NVIC 配置,外设到内存(DR->USART1)
  48.    * @param  无
  49.   * @retval 无
  50.   */
  51. void USARTx_DMA_Config(void)
  52. {
  53.                 DMA_InitTypeDef DMA_InitStructure;

  54.                 // 开启DMA时钟
  55. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  56.                 // 设置DMA源地址:串口数据寄存器地址*/
  57. DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
  58.                 // 内存地址(要传输的变量的指针)
  59. DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ReceiveBuff;
  60.                 // 方向:从外设到内存
  61. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  62.                 // 传输大小        
  63. DMA_InitStructure.DMA_BufferSize = RECEIVEBUFF_SIZE;
  64.                 // 外设地址递增
  65. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
  66.                 // 内存地址自增
  67. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  68.                 // 外设数据单位        
  69. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  70.                 // 内存数据单位
  71. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         
  72.                 // DMA模式,一次或者循环模式
  73. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
  74.                 //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;        
  75.                 // 优先级:中        
  76. DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  77.                 // 禁止内存到内存的传输
  78. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  79.                 // 配置DMA通道                  
  80. DMA_Init(USART_RX_DMA_CHANNEL, &DMA_InitStructure);
  81.                 // 使能DMA
  82.                 DMA_Cmd (USART_RX_DMA_CHANNEL,ENABLE);
  83. }


  84. //重新恢复DMA指针
  85. void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
  86. {
  87.      DMA_Cmd(DMA_CHx, DISABLE );  //关闭USART1 RX DMA1所指示的通道
  88.     DMA_SetCurrDataCounter(DMA_CHx, RECEIVEBUFF_SIZE);//DMA通道的DMA缓存的大小
  89.     DMA_Cmd(DMA_CHx, ENABLE);  //打开USART1 RX DMA1所指示的通道
  90. }

  91. /**
  92.    * @brief  USARTx RX NVIC 配置,外设到内存(DR->USART1)
  93.    * @param  无
  94.   * @retval 无
  95.   */
  96. void USARTx_NVIC_Config(void)
  97. {
  98.         NVIC_InitTypeDef NVIC_InitStructure;
  99.      /* Configure the NVIC Preemption Priority Bits */

  100.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);

  101.      /* Enable the USART Interrupt */

  102.      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

  103.      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

  104.      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  105.      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  106.      NVIC_Init(&NVIC_InitStructure);

  107. }

  108. //串口中断函数
  109. void USART1_IRQHandler(void)                //串口1中断服务程序
  110. {

  111. uint8_t Usart1_Rec_Cnt;

  112.       if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
  113.        {
  114.            USART_ReceiveData(USART1);//读取数据注意:这句必须要,否则不能够清除中断标志位。
  115.           Usart1_Rec_Cnt = RECEIVEBUFF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度

  116.          //***********帧数据处理函数************//
  117.            printf ("Thelenght:%drn",Usart1_Rec_Cnt);
  118.            printf ("The data:rn");

  119.            Usart_SendArray(DEBUG_USARTx, ReceiveBuff, RECEIVEBUFF_SIZE);
  120.            memset();

  121.            printf ("rnOver! rn");
  122.          //*************************************//
  123.           USART_ClearITPendingBit(USART1,USART_IT_IDLE);         //清除中断标志
  124.          MYDMA_Enable(DMA1_Channel5);                  //恢复DMA指针,等待下一次的接收
  125.      }

  126. }

  127. __IO uint16_t ADC_ConvertedValue[NOFCHANEL]={0,0};

  128. /**
  129.    * @brief  ADC GPIO 初始化
  130.   * @param  无
  131.   * @retval 无
  132.   */
  133. static void ADCx_GPIO_Config(void)
  134. {
  135.         GPIO_InitTypeDef GPIO_InitStructure;

  136.         // 打开 ADC IO端口时钟
  137. ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );

  138.         // 配置 ADC IO 引脚模式
  139. GPIO_InitStructure.GPIO_Pin =         ADC_PIN1|ADC_PIN2;  //|ADC_PIN3|ADC_PIN4|ADC_PIN5|ADC_PIN6;
  140.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

  141.         // 初始化 ADC IO
  142.         GPIO_Init(ADC_PORT, &GPIO_InitStructure);                                
  143. }

  144. /**
  145.    * @brief  配置ADC工作模式
  146.   * @param  无
  147.   * @retval 无
  148.   */
  149. static void ADCx_Mode_Config(void)
  150. {
  151.         DMA_InitTypeDef DMA_InitStructure;
  152.         ADC_InitTypeDef ADC_InitStructure;

  153.         // 打开DMA时钟
  154. RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);
  155.         // 打开ADC时钟
  156. ADC_APBxClock_FUN ( ADC_CLK, ENABLE );

  157.         // 复位DMA控制器
  158. DMA_DeInit(ADC_DMA_CHANNEL);

  159.         // 配置 DMA 初始化结构体
  160. // 外设基址为:ADC 数据寄存器地址
  161. DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADC_x->DR ) );

  162.         // 存储器地址
  163. DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;

  164.         // 数据源来自外设
  165. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  166.         // 缓冲区大小,应该等于数据目的地的大小
  167. DMA_InitStructure.DMA_BufferSize = NOFCHANEL;

  168.         // 外设寄存器有两个,地址需要递增
  169. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

  170.         // 存储器地址递增
  171. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  172.         // 外设数据大小为半字,即两个字节
  173. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  174.         // 内存数据大小也为半字,跟外设数据大小相同
  175. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  176.         // 循环传输模式
  177. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;        

  178.         // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
  179. DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  180.         // 禁止存储器到存储器模式,因为是从外设到存储器
  181. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  182.         // 初始化DMA
  183.         DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);

  184.         // 使能 DMA 通道
  185. DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);

  186.         // ADC 模式配置
  187. // 只使用一个ADC,属于单模式
  188. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

  189.         // 扫描模式
  190. ADC_InitStructure.ADC_ScanConvMode = ENABLE ;

  191.         // 连续转换模式
  192. ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  193.         // 不用外部触发转换,软件开启即可
  194. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

  195.         // 转换结果右对齐
  196. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  197.         // 转换通道个数
  198. ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;        

  199.         // 初始化ADC
  200.         ADC_Init(ADC_x, &ADC_InitStructure);

  201.         // 配置ADC时钟N狿CLK2的8分频,即9MHz
  202.         RCC_ADCCLKConfig(RCC_PCLK2_Div8);

  203.         // 配置ADC 通道的转换顺序和采样时间
  204. ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL1, 1, ADC_SampleTime_55Cycles5);
  205.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL2, 2, ADC_SampleTime_55Cycles5);
  206.         //ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL3, 3, ADC_SampleTime_55Cycles5);
  207.         //ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL4, 4, ADC_SampleTime_55Cycles5);
  208.         //ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL5, 5, ADC_SampleTime_55Cycles5);
  209.         //ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL6, 6, ADC_SampleTime_55Cycles5);

  210.         // 使能ADC DMA 请求
  211. ADC_DMACmd(ADC_x, ENABLE);

  212.         // 开启ADC ,并开始转换
  213. ADC_Cmd(ADC_x, ENABLE);

  214.         // 初始化ADC 校准寄存器  
  215. ADC_ResetCalibration(ADC_x);
  216.         // 等待校准寄存器初始化完成
  217. while(ADC_GetResetCalibrationStatus(ADC_x));

  218.         // ADC开始校准
  219. ADC_StartCalibration(ADC_x);
  220.         // 等待校准完成
  221. while(ADC_GetCalibrationStatus(ADC_x));

  222.         // 由于没有采用外部触发,所以使用软件触发ADC转换
  223. ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
  224. }

  225. /**
  226.    * @brief  ADC初始化
  227.   * @param  无
  228.   * @retval 无
  229.   */
  230. void ADCx_Init(void)
  231. {
  232.         ADCx_GPIO_Config();
  233.         ADCx_Mode_Config();
  234. }
  235. /*********************************************END OF FILE**********************/


  236. /**
  237.    * @brief  主函数
  238.   * @param  无  
  239.    * @retval 无
  240.   */
  241. int main ( void )
  242. {        
  243.         /* 初始化USART */
  244.         USART_Config();

  245.         /* 配置使用DMA模式 */
  246. USARTx_DMA_Config();

  247.         USARTx_NVIC_Config();
  248.         // ADC 初始化
  249. ADCx_Init();

  250.         printf("rnAPP begin... rn");

  251.         xTaskCreate( vTaskStart, "Task Start", 512, NULL, 1, NULL );
  252.         vTaskStartScheduler();
  253. }

  254. void vTaskADC( void * pvParameters )
  255. {
  256.         while (1)
  257.         {

  258.                         ADC_ConvertedValueLocal[0] =(float) ADC_ConvertedValue[0]/4096*3.3;
  259.                         ADC_ConvertedValueLocal[1] =(float) ADC_ConvertedValue[1]/4096*3.3;
  260.                         //ADC_ConvertedValueLocal[2] =(float) ADC_ConvertedValue[2]/4096*3.3;
  261.                         //ADC_ConvertedValueLocal[3] =(float) ADC_ConvertedValue[3]/4096*3.3;
  262.                         //ADC_ConvertedValueLocal[4] =(float) ADC_ConvertedValue[4]/4096*3.3;
  263.                         //ADC_ConvertedValueLocal[5] =(float) ADC_ConvertedValue[5]/4096*3.3;

  264.                         printf("rn CH0 value = %f V rn",ADC_ConvertedValueLocal[0]);
  265.                         printf("rn CH1 value = %f V rn",ADC_ConvertedValueLocal[1]);
  266.                         //printf("rn CH2 value = %f V rn",ADC_ConvertedValueLocal[2]);
  267.                         //printf("rn CH3 value = %f V rn",ADC_ConvertedValueLocal[3]);
  268.                         //printf("rn CH4 value = %f V rn",ADC_ConvertedValueLocal[4]);
  269.                         //printf("rn CH5 value = %f V rn",ADC_ConvertedValueLocal[5]);

  270.                         printf("rnrn");
  271.                         Delay(0xffffee);
  272.         }
  273. }

回帖(5)

訾存贵

2018-8-28 11:35:31
同一时刻只能使能一个channel吧
The 7 requests from the peripherals (TIMx[1,2,3,4], ADC1, SPI1, SPI/I2S2, I2Cx[1,2] and USARTx[1,2,3]) are simply logically ORed before entering the DMA1, this means that only one request must be enabled at a time.
另外串口只有一个数据寄存器,你确定使用DMA_PeripheralInc_Enable时数据正常吗?
举报

王静

2018-8-28 11:35:59
好像一个dma同一时刻只能处理一个通道的数据,同时有两路通道数据过来,有问题。两个通道数据接收无法实现吗?因为没办法保证这样的条件啊。
举报

贾埃罗

2018-8-28 11:36:38
其实adc的数据是主控主动读取的,可以不要dma方式的。我想请问,直接读取adc的值,不用dma,可以做到吗?
举报

訾存贵

2018-8-28 11:37:02
其实adc的数据是主控主动读取的,可以不要dma方式的。我想请问,直接读取adc的值,不用dma,可以做到吗?
举报

贾埃罗

2018-8-28 11:37:25
经过我不断的调试,终于找到了解决办法。就是在usart中断中重新运行 USARTx_DMA_Config()。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分