历史上的今天
返回首页

历史上的今天

今天是:2024年12月30日(星期一)

正在发生

2021年12月30日 | STM32F103单片机使用DMA功能读取ADC采样数据

2021-12-30 来源:eefocus

使用DMA功能操作外设时,可以极大的简化代码,提高程序的执行效率。特别是在需要频繁操作的外设上。比如现在要采集单片机16个ADC通道的电压值,就可以使用DMA功能,直接将ADC通道转换好的值,传输到数组中。需要操纵ADC的值时,直接去数组中拿数据就行。不需要再去判断ADC数据转换是否结束。下面直接通过代码来实现。


首先初始化ADC,这里将ADC的16个采样通道全部开启。


void ADC1_Init ( void )

{

    GPIO_InitTypeDef GPIO_InitStructure;

    ADC_InitTypeDef  ADC_InitStructure;  

    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE );

    RCC_ADCCLKConfig ( RCC_PCLK2_Div6 ); // 72M / 6 = 12M  ADC最大不能超过14M

    

    // ADC1 --- ADC8

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init ( GPIOA, &GPIO_InitStructure );

    // ADC9 ADC10

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init ( GPIOB, &GPIO_InitStructure );

   // ADC11 --- ADC 16

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init ( GPIOC, &GPIO_InitStructure );

    

    ADC_DeInit ( ADC1 );

   

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式

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

    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐

    ADC_InitStructure.ADC_NbrOfChannel = 16; //ADC通道数

    ADC_Init ( ADC1, &ADC_InitStructure );

    

    //规则通道配置

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_8, 9, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_9, 10, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_10, 11, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_11, 12, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_12, 13, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_13, 14, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_14, 15, ADC_SampleTime_239Cycles5 );

    ADC_RegularChannelConfig ( ADC1, ADC_Channel_15, 16, ADC_SampleTime_239Cycles5 );

    

   ADC_DMACmd ( ADC1, ENABLE ); //使能ADC DMA传输

   

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

    ADC_ResetCalibration ( ADC1 ); //使能复位校准

    while ( ADC_GetResetCalibrationStatus ( ADC1 ) ); //等待复位校准结束

    ADC_StartCalibration ( ADC1 ); //开启AD校准

    while ( ADC_GetCalibrationStatus ( ADC1 ) ); //等待校准结束

//    ADC_SoftwareStartConvCmd ( ADC1, ENABLE ); //启动转换

}


ADC设置为扫描模式,连续转换,16个通道依次扫描采样,一轮采样结束后,接着开启下一轮采样。


下面初始化DMA功能。


void MYDMA_Config ( DMA_Channel_TypeDef *DMA_CHx, u32 cpar, u32 cmar, u16 cndtr )

{

    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_DMA1, ENABLE );

    DMA_DeInit ( DMA_CHx );

    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //外设基地址

    DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //内存基地址

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输从外设到内存

    DMA_InitStructure.DMA_BufferSize = cndtr; //DMA缓存

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不变

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据16位

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存地址1位

    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环工作模式

    DMA_InitStructure.DMA_Priority = DMA_Priority_High; //高优先级

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //没有设置内存到内存传输

    DMA_Init ( DMA_CHx, &DMA_InitStructure );

}


这里DMA的数据方向要设置为从外设到内存,也就是将外设ADC采样的数据结果保存到内部存储空间中。


初始化完成之后,在主函数中直接启动DMA转换功能。


#define ADC1_DR_Address    ((uint32_t)0x4001244C)

u16 AD_Value[6];

float volta[16];

u8 i, j;

uint16_t ADC1ConvertedValue[10][16];

uint32_t ADC1ConvertedVoltage[16];

int main ( void )

{

    delay_init();       //延时函数初始化

    NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );

    uart_init ( 115200 );

    LED_Init();         //初始化与LED连接的硬件接口

    MYDMA_Config ( DMA1_Channel1, ( u32 ) &ADC1->DR, ( u32 ) &ADC1ConvertedValue, 160 );

    ADC1_Init();

    DMA_Cmd ( DMA1_Channel1, ENABLE );          //启动DMA通道

    ADC_SoftwareStartConvCmd ( ADC1, ENABLE );  //启动ADC1软件转换

    while ( 1 )

    {

        ADC1ConvertedVoltage[0] = 0;

        for ( i = 0; i < 16; i++ )

        {

            ADC1ConvertedVoltage[i] = 0;

            for ( j = 0; j < 10; j++ ) //采样10次取平均值

            {

                ADC1ConvertedVoltage[i] += ADC1ConvertedValue[j][i];

            }

            ADC1ConvertedVoltage[i] = ADC1ConvertedVoltage[i] / 10;

        }

for(i=0;i<16;i++)

{

volta[i] = ADC1ConvertedVoltage[i] * 3.3 / 4096;

printf("AD%2d:  value: %4d  vol: %frn",i,ADC1ConvertedVoltage[i],volta[i]);


}

printf ( "rnrn" );

       

        LED0 = 0;

        LED1 = 1;

        delay_ms ( 500 ); //延时300ms

        LED0 = 1;

        LED1 = 0;

        delay_ms ( 500 ); //延时300ms

    }

}


通过一个二维数据存储16个通道的转换值,每个通道存储10个数据然后取平均值。最后将采样的16个通道值依次打印出来。

推荐阅读

史海拾趣

安森德(Ascend)公司的发展小趣事

随着产品技术的成熟,安森德公司开始积极拓展市场。公司凭借优质的产品和服务,成功进入工业电源、电机驱动、消费电子等多个领域。同时,安森德积极寻求与全球顶尖企业的战略合作,通过与这些企业的技术交流和业务合作,不断提升自身的技术水平和市场竞争力。这些合作不仅为安森德带来了更多的商业机会,也进一步提升了公司在行业内的知名度和影响力。

Daniels Manufacturing公司的发展小趣事

进入21世纪后,随着信息技术的快速发展,数字化转型成为制造业的重要趋势。DMC紧跟时代步伐,积极推进数字化转型和智能制造。通过引入先进的生产管理系统、自动化生产线和智能检测设备,DMC实现了生产过程的数字化、网络化和智能化。这不仅提高了生产效率和产品质量,还降低了生产成本和能源消耗。此外,DMC还利用大数据和人工智能技术,对市场需求进行精准预测和分析,为产品研发和市场营销提供有力支持。

Federal Custom Cable公司的发展小趣事

在追求企业发展的同时,Federal Custom Cable也积极履行社会责任。他们注重绿色生产,采用环保材料和生产工艺,减少对环境的影响。同时,Federal Custom Cable还积极参与公益事业和慈善活动,回馈社会。这种关注社会责任、追求绿色发展的企业精神,使Federal Custom Cable在电缆行业中树立了良好的企业形象。

Hoffman Engineering公司的发展小趣事

1945年,年轻的Harry Hoffman凭借对工厂安全的深切关注,发明了前所未有的压力机安全保护装置。这一装置能够在操作人员的手进入危险区域时迅速停止机器,极大地保护了生产工厂中员工的人身安全。这一创新不仅为Hoffman Engineering奠定了技术基础,也开启了公司在工业安全领域的先河。Harry的发明迅速获得市场认可,为公司的后续发展奠定了坚实的基础。

ARBOR公司的发展小趣事

ARBOR公司一直致力于电子技术的研发与创新。在某个时期,公司研发团队成功开发出一款具有颠覆性的电路板技术,这项技术在信号传输速度和稳定性上实现了重大突破。凭借这一技术,ARBOR公司迅速占领了高端电子市场,成为行业内的技术领导者。公司股价随之飙升,吸引了大量投资者的关注。

Daburn公司的发展小趣事

在Daburn公司的发展历程中,质量控制一直是重中之重。公司建立了严格的质量管理体系,从原材料采购到生产流程再到成品检验,每一个环节都严格把控。此外,Daburn还注重持续改进,通过引入先进的生产设备和工艺,不断提高产品的质量和性能。这种对质量的执着追求让Daburn赢得了客户的信任和好评。

问答坊 | AI 解惑

塑封料发展状况及其工艺选择

[ip]塑封料发展状况及其工艺选择 上海常祥实业有限公司   刘志:13611616628 引言 塑封料,又称环氧塑封料(EMC,Epoxy Molding Compound)以其高可靠性、低成本、生产工艺简单、适合大规模生产等特点,占据了整个微电子封装材料97%以上的市场。 ...…

查看全部问答>

日本常用三极管

这是在我的硬盘里的资料,拿出来共享一下。希望能对大家有参考价值。…

查看全部问答>

智能手机的操作系统,哪个比较人性化?

最好把塞班 WM linux 黑莓OS...乱七八糟的挨个试用一遍,哈哈 你们觉得呢?…

查看全部问答>

99SE中写PCB中文字体

1、解压后将此文件放入C盘   2、在放入C盘后,在FONT.EXE文件中编辑你所要放的汉字   3、编辑好汉字后,在PROTEL99SE的PCB状态下,找到你放入PROTELHZ文件夹的路径,导入PCBHZ.LIB文件      采用以上步 ...…

查看全部问答>

一种简易高精度频率信号发生器的设计与实现

一种简易高精度频率信号发生器的设计与实现…

查看全部问答>

WinCE6.0修改.cpl文件属性

包括去掉文件保护,只读,隐藏等。(用代码的哦)…

查看全部问答>

飞行体验项目——看看这样的项目谁能作

项目:飞行体验项目 说明:         飞行体验装置由现时屏幕和控制器两部分组成,控制器为飞鸟外形,小朋友们可以俯卧在控制器上操作飞行器,电脑模拟的飞行场景以及小朋友的操作结果会在显示屏幕上显示  &n ...…

查看全部问答>

IAR5.XX关于实时查看变量变化的功能

在STVD(调试STM8)里watch变量有"ON THE FLY"可以实时查看变量的变化。 在IAR5.XX调试STM32F103XXX不知道有没有这样的功能??? 或者类似的功能也行啊??? 请IAR EARM 高手指点!!!…

查看全部问答>

关于NE555的问题。当输入高电平,输出低电平不够低怎么办?量出来2.7。

做单稳电路。高电平3.7,低电平2.7。 [ 本帖最后由 huang91 于 2011-11-10 15:49 编辑 ]…

查看全部问答>