打印
[STM32F1]

stm32F103——ADC与DMA(按键与光敏电阻)

[复制链接]
楼主: 我爱台妹mmd
手机看帖
扫描二维码
随时随地手机跟帖
21
我爱台妹mmd|  楼主 | 2023-11-26 01:03 | 只看该作者 |只看大图 回帖奖励 |倒序浏览


当ADC外设时钟为56Mhz的时候:(ADC模块工作频率为14Mhz)

        采样时间为:

        转换时间为:1.5 *   +  12.5 *    =   14 *   = 1us

当ADC外设时钟为72Mhz的时候:(ADC模块工作频率为12Mhz)

        采样时间为:

        转换时间为:1.5*   +  12.5 *    =   14 *   = 1.17us

注意:采样时间系数1.5,是可以通过编程更改的

使用特权

评论回复
22
我爱台妹mmd|  楼主 | 2023-11-26 01:03 | 只看该作者


   ADC模块采样,是不需要CPU参与的(除非设置了ADC采样时产生中断)。我们在ADC采样到数据后,一般是使用DMA将数据存储到内存中,因为,如果每次都用中断来进行ADC采样数据和数据存储的话,那么CPU资源就会被ADC采样和存储数据操作给霸占,这样会浪费大量的CPU资源。(重点)

         注意:ADC是不断循环的对通道进行采样。但是,DMA是来一个数据就搬运一次,而不是不管有没有数据来,它都在哪里循环搬运。

自校准:ADC在使能之后是需要进行校准的。否则,采样的数值不准确。

使用特权

评论回复
23
我爱台妹mmd|  楼主 | 2023-11-26 01:03 | 只看该作者
模拟数字转换规则

    1>规则转换:按照程序设定好的依次进行转换(即:几秒钟转换一次)
    2>注入转换:类似于中断,当注入转换触发时,先进行注入转换,再继续规则转换(即:当注入转换触发时时,先转换注入转换的数据,转换完注入转换触发的数据后,在来执行程序中已经规定好的规则转换。也就是说,注入转换会抢占规则转换)

注意:规则转换和注入转换都有外部触发选项

使用特权

评论回复
24
我爱台妹mmd|  楼主 | 2023-11-26 01:04 | 只看该作者
ADC怎样对读取到的数据进行处理:
我们现在需要读取按键产生的分压值和光敏电阻产生的分压值,如果对这两个通道进行循环扫描(即:读取一次ADCkey,下一次读取光敏电阻,然后反复循环)。但是数据该怎么处理呢?

我们可以建立一个二维数组data[key][guan_ming],如下:



         每个外设都读取50个数值,把它们放在二维数组data[key][guan_ming]中,然后将这50个数求平均值,此时这个平均值才是较为接近的正确的值。

使用特权

评论回复
25
我爱台妹mmd|  楼主 | 2023-11-26 01:04 | 只看该作者
ADC内部框图

使用特权

评论回复
26
我爱台妹mmd|  楼主 | 2023-11-26 01:04 | 只看该作者
      我们可以看到注入转换数据寄存器(4x16bit)而规则转换数据寄存器(16bit)说明注入转换数据寄存器有4个16bit的寄存器,而规则转换数据寄存器只有1个16bit的寄存器。

使用特权

评论回复
27
我爱台妹mmd|  楼主 | 2023-11-26 01:04 | 只看该作者

使用特权

评论回复
28
我爱台妹mmd|  楼主 | 2023-11-26 01:05 | 只看该作者

使用特权

评论回复
29
我爱台妹mmd|  楼主 | 2023-11-26 01:05 | 只看该作者
模拟看门狗事件:我们设置一个数值范围   低门限~高门限,如果ADC读到的值不在这个数值范围内,那么模拟看门狗就会触发一个中断/事件。然后程序进行相应的处理。

使用特权

评论回复
30
我爱台妹mmd|  楼主 | 2023-11-26 01:05 | 只看该作者
编程步骤:
ADC采集AD按键和光敏电阻的电压值,编程步骤:
1,打开时钟--------ADC1, GPIOC, AFIO, DMA1
2.,ADC预分频器-------6分频-----ADCCLK = 12MHZ
3,初始化GPIOC
-------GPIO_Pin_0 | GPIO_Pin_1
-------模拟输入
4.初始化ADC1
-------模式-----ADC独立模式
-------是否扫描-----是
-------是否连续转换----是
-------对齐方式---右对齐
-------是否使用外部触发------否
-------通道数目-----2
5,使能ADC的DMA
6,DMA初始化
-------外设基地址--------&ADC 1->DR(即:规则数据寄存器ADC_DR)
-------内存基地址--------二维数组 ADC_DATA[50][2]  (即:二维数组)(50 * 2 = 100个数据)
-------方式----外设作为数据来源
-------外设地址是否递增------否(即:ADC地址----不自增)
-------内存地址是否递增------是(即:二维数组地址----自增 )
-------外设数据传输的宽度-----半字(每次搬运两个字节宽度)(因为2^8 = 256,而ADC采样的数值在0~4095,所以只能使用两个字节(即半字)来表示,2^16 = 65535)
-------内存数据传输的宽度-----半字
-------传输的数目-----100(100个字节)
-------模式-----循环模式
-------内存到内存是否使能----否(如果设置了外设到内存的话,那么内存到内存就要失能)
-------优先级---高

7,使能DMA1通道1(只有DMA1通道1可以搬运ADC1的数据)
8,配置通道10和11的采样顺序和采样时间
9,使能ADC1

10,校准
    ------复位校准寄存器
    ------等待复位成功
    ------开始校准
    ------等待校准成功
11,软件触发ADC(有外部触发ADC和软件触发ADC。外部触发ADC需要发生中断)

使用特权

评论回复
31
我爱台妹mmd|  楼主 | 2023-11-26 01:05 | 只看该作者
库函数

按键与光敏电阻的引脚分别为PC0和PC1,这两个对于的ADC通道为通道10和通道11

使用特权

评论回复
32
我爱台妹mmd|  楼主 | 2023-11-26 01:05 | 只看该作者

使用特权

评论回复
33
我爱台妹mmd|  楼主 | 2023-11-26 01:06 | 只看该作者

使用特权

评论回复
34
我爱台妹mmd|  楼主 | 2023-11-26 01:06 | 只看该作者
设置采样通道、采样通道的顺序Rank与采样时间ADC_SampleTime。采样顺序就是,比如通道11设置为1,通道10设置为2,那么先采集通道11的数据,再采集通道10的数据。采样时间,如下图:

使用特权

评论回复
35
我爱台妹mmd|  楼主 | 2023-11-26 01:06 | 只看该作者
注意:采样时间越长,采样出来的数据越准确。在12Mhz频率下,最长的239.5个周期就是21us,采样50个数据总共也就花费21* 50 = 1050us的时间(即1.05ms),对于整个按键动作来说,这个时间非常短。


注意:获取ADC校准寄存器的状态标志位与以往的不一样。它是正在执行校准初始化的过程中时,标志位置1。已经完成校准初始化时,标志位置0。

        注意:ADC要在使能之后,才能开始进行校准。

使用特权

评论回复
36
我爱台妹mmd|  楼主 | 2023-11-26 01:07 | 只看该作者
编写代码

#define ADC_CH 2
#define ADC_data_size 50
uint16_t ADC_DATA[ADC_data_size][ADC_CH];        //用来存储数据的二维数组

void ADC1_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    ADC_InitTypeDef ADC_InitStruct;
    DMA_InitTypeDef DMA_InitStruct;
    // 1,打开时钟----ADC1,GPIOC,AFIO,DMA1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

    // 2,ADC预分频器---6分频---ADCCLK=12MHZ
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    // 3,初始化GPIOC
    GPIO_InitStruct.GPIO_Pin    =GPIO_Pin_0|GPIO_Pin_1;
    GPIO_InitStruct.GPIO_Mode   =GPIO_Mode_AIN;
    GPIO_Init(GPIOC,&GPIO_InitStruct);

    // 4,初始化ADC1
    ADC_InitStruct.ADC_ContinuousConvMode   =ENABLE;
    ADC_InitStruct.ADC_DataAlign            =ADC_DataAlign_Right;
    ADC_InitStruct.ADC_ExternalTrigConv     =ADC_ExternalTrigConv_None;
    ADC_InitStruct.ADC_Mode                 =ADC_Mode_Independent;
    ADC_InitStruct.ADC_NbrOfChannel         =ADC_CH;        //宏定义ADC_CH = 2
    ADC_InitStruct.ADC_ScanConvMode         =ENABLE;
    ADC_Init(ADC1,&ADC_InitStruct);

    // 5,使能ADC的DMA
    ADC_DMACmd(ADC1,ENABLE);

    // 6,DMA初始化
    DMA_InitStruct.DMA_PeripheralBaseAddr   =(uint32_t)&ADC1->DR;      
    DMA_InitStruct.DMA_MemoryBaseAddr       =(uint32_t)ADC_DATA;  /*这里强转为(uint32_t)类型,是因为在结构体DMA_InitStruct里面,成员DMA_MemoryBaseAddr是uint32_t类型的*/
    DMA_InitStruct.DMA_DIR                  =DMA_DIR_PeripheralSRC;
    DMA_InitStruct.DMA_PeripheralInc        =DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc            =DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_PeripheralDataSize   =DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryDataSize       =DMA_MemoryDataSize_HalfWord;
    DMA_InitStruct.DMA_BufferSize           =ADC_CH*ADC_data_size;
    DMA_InitStruct.DMA_M2M                  =DMA_M2M_Disable;
    DMA_InitStruct.DMA_Mode                 =DMA_Mode_Circular;
    DMA_InitStruct.DMA_Priority             =DMA_Priority_High;
    DMA_Init(DMA1_Channel1,&DMA_InitStruct);

    // 7,使能DMA1通道1
    DMA_Cmd(DMA1_Channel1, ENABLE);

    // 8,配置通道10和通道11的采样顺序和采样时间
    ADC_RegularChannelConfig(ADC1,ADC_Channel_10, 1,ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_11, 2,ADC_SampleTime_239Cycles5);

    // 9,使能ADC1
    ADC_Cmd(ADC1,ENABLE);

    // 10,校准
    ADC_ResetCalibration(ADC1);
    while(SET==ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(SET==ADC_GetCalibrationStatus(ADC1));

    // 11,软件触发ADC
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}


uint16_t ADC_RG_Value(void)        //将采集到的50个光敏电阻电压的数据累加起来,然后求平均值
{
    uint32_t SUM=0;
    uint8_t i;
    for(i=0;i<ADC_data_size;i++){
        SUM=SUM+ADC_DATA[i][0];
    }
    return (uint16_t)(SUM/ADC_data_size);
}

uint16_t ADC_KEY_Value(void)        //将采集到的50个按键电压的数据累加起来,然后求平均值
{
    uint32_t SUM=0;
    uint8_t i;
    for(i=0;i<ADC_data_size;i++){
        SUM=SUM+ADC_DATA[i][1];
    }
    return (uint16_t)(SUM/ADC_data_size);
}


int main(void)
{
   
    RCC_ConfigTo72M();
    Systick_Config(72);
    DMA1CH2_Config(SRC,DRC,data_size);
    ADC1_Config();
    while(1){
        printf("ADC_RG_Value=%d\n",ADC_RG_Value());
        printf("ADC_KEY_Value=%d\n",ADC_KEY_Value());

   }
}

注意:DMA搬运数据,是来一个数据搬运一次,而不是,不管来不来数据它都独自一人,在一个孤独的角落默默的搬运。

使用特权

评论回复
37
周半梅| | 2024-7-21 08:19 | 只看该作者

共模电感的电感值可以用电桥来测量

使用特权

评论回复
38
童雨竹| | 2024-7-21 11:18 | 只看该作者

共模电感一个以铁氧体为磁芯的共模干扰抑制器件

使用特权

评论回复
39
Wordsworth| | 2024-7-21 12:21 | 只看该作者

通过缩回铜壳,可以保护电镀免受机械损坏。

使用特权

评论回复
40
Clyde011| | 2024-7-21 13:24 | 只看该作者

脉冲变压器的原/副边相位关系,

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则