Chinaunix首页 | 论坛 | 博客
  • 博客访问: 163151
  • 博文数量: 73
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 235
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-27 09:43
个人简介

为兴趣挑灯夜战

文章分类
文章存档

2018年(4)

2017年(7)

2016年(9)

2015年(4)

2014年(49)

分类: 嵌入式

2018-03-13 23:46:14

在此之前,使用stm32的ADC采集信号,使用到的通道就只有一个,用的时候也是别人写好的代码,没去研究,然而最近用GD32F350单片机作一个电源板时,要采集6个通道的信号,所以就仔细看了手册,有规则通道和注入通道两个概念,按概念,规则通道是按顺序采集,注入通道可以最多设备四个,有独立的保存采集数据的寄存器。如果超过4个就不能没每个每个通道对应一个数据寄存器;如果是规则通道,当通道数大于一时是可以先设置采集通道再读数据,但是我想要的是像手册上说大的一次就把6个通道的数据采集出来,但是规则通道只有一个数据寄存器,如何知道每一次采集的数据是对应哪一个通道呢?最后问了一个做电源有经验的人,他说使用DMA,设置数据长度为6个,然后每个通道采集的的数据就按顺序存到指定的地址了,真是一语惊醒梦中人啊。看看代码吧:

  1. void dma_config(void)
  2. {
  3.     dma_parameter_struct dma_init_struct;

  4.         rcu_periph_clock_enable(RCU_DMA);
  5.     /* initialize DMA channel0 */
  6.     dma_deinit(DMA_CH0);
  7.     dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
  8.     dma_init_struct.memory_addr = (uint32_t)ad_value;//指定DMA数据空间地址
  9.     dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  10.     dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
  11.     dma_init_struct.number = 48;
  12.     dma_init_struct.periph_addr = (uint32_t)&(ADC_RDATA);
  13.     dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  14.     dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
  15.     dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  16.     dma_init(DMA_CH0, dma_init_struct);
  17.     
  18.     /* configure DMA mode */
  19.     dma_circulation_enable(DMA_CH0);
  20.     dma_memory_to_memory_disable(DMA_CH0);
  21.     
  22.     /* enable DMA channel0 */
  23.     dma_channel_enable(DMA_CH0);
  24.     dma_interrupt_enable(DMA_CH0, DMA_INT_FTF);
  25.     nvic_irq_enable(DMA_Channel0_IRQn , 0U, 0U);//配置中断优先级
  26. }

  27. void ADCSampleInit(void)
  28. {

  29. //    rcu_periph_clock_enable(RCU_GPIOB);    
  30. //    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
  31. // gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
  32.     
  33.     dma_config();    
  34.     // ADCCLK = PCLK2/6
  35.     rcu_adc_clock_config(RCU_ADCCK_APB2_DIV4);// ADC时钟27MHz
  36.     rcu_periph_clock_enable(RCU_ADC);
  37.     rcu_periph_clock_enable(RCU_GPIOA);
  38.     
  39.     //PA2,3,4,5,6
  40.     gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE,
  41.                                 GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6);
  42.     
  43.     // ADC channel length config 设置规则组的数量,转换扫描时按此数量扫描
  44.     adc_channel_length_config(ADC_REGULAR_CHANNEL, 6);

  45.     /* ADC regular channel config */
  46.     adc_regular_channel_config(0, ADC_CHANNEL_2, ADC_SAMPLETIME_1POINT5);
  47.     adc_regular_channel_config(1, ADC_CHANNEL_3, ADC_SAMPLETIME_1POINT5);
  48.     adc_regular_channel_config(2, ADC_CHANNEL_4, ADC_SAMPLETIME_1POINT5);
  49.     adc_regular_channel_config(3, ADC_CHANNEL_5, ADC_SAMPLETIME_1POINT5);
  50.     adc_regular_channel_config(4, ADC_CHANNEL_6, ADC_SAMPLETIME_1POINT5);
  51.     //Vrefin
  52.     adc_regular_channel_config(5, ADC_CHANNEL_17, ADC_SAMPLETIME_13POINT5);//ADC_SAMPLETIME_13POINT5 1515 //ADC_SAMPLETIME_28POINT5 1462
  53.     //adc_regular_channel_config(5, ADC_CHANNEL_16, ADC_SAMPLETIME_13POINT5);
  54.     // Vrefin enable
  55.     adc_tempsensor_vrefint_enable();
  56.     /* ADC external trigger enable */
  57.     adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
  58.     /* ADC external trigger source config */
  59.     adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
  60.         
  61.     /* ADC data alignment config */
  62.     adc_data_alignment_config(ADC_DATAALIGN_RIGHT);//数据为右对齐
  63.     /* enable ADC interface */
  64.     adc_enable();
  65.     /* ADC calibration and reset calibration */
  66.     adc_calibration_enable();
  67.     /* ADC SCAN function enable */
  68.     adc_special_function_config(ADC_SCAN_MODE, ENABLE);//使能扫描模式
  69.     /* ADC continuous mode function enable */        
  70.     adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE); //连续模式
  71.     /* ADC DMA function enable */
  72.     adc_dma_mode_enable();//使用ADC DMA, ADC的数据将会存入DMA模块中,这是定义的DMA数据空间为ad_value[]
  73.     
  74.     adc_software_trigger_enable(ADC_REGULAR_CHANNEL);// 软件出发一次采样


原来就这个简单。
这里还要注意一个问题,就是采样时间,采样时间越短,输入的阻抗越小,这是如果你的信号是经过电阻分压后接入单片机的,那输入阻抗会改变电路设计上的分压比例,这时就要通过测量校准实际的比例值,比如电压经过300k+200K的电阻接到地,从两个电阻中间取信号,按电阻比例算分压比例是2/(3+2)=0.4,但若设置采样时间为1.5T,实际测出的比例是0.3355。
另一个是基准电压问题,如果VDDA不怎么稳定,会导致调试代码是容易中断,还有就是采集到的信号和实际偏差很大,这是可以通过采集弹片内部1.2V基准电压Vrefin得到的值反推出实际的VDDA的值,即实际采样值Vin=1.2xVrefinADC/VrefinADC.

阅读(1430) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~