本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

【青风带你学stm32f051系列教程】第10课 ADC采样/DMA通道
发布时间:2013-01-18
分享到:
【青风带你学stm32f051系列教程】第10课 ADC采样/DMA通道
发布时间:2013-01-18
分享到:

第10 课   ADC采样/DMA通道

模数转换器 (ADC) 外设用于将连续的模拟电压转换成离散的数字量。Stm32f051包含一个分辨率为12位的ADC模块,同时具有19个ADC通道,其中16个外部采样通道和3个内部信号源。ADC采样通道源和ADC管脚如下表所示:

本实验我们采样ADC_IN选取其中一个管脚作为输入引脚,需要对 ADC进行配置。需要配置的几个参数:ADC转化分辨率 ,配置采样的采样方式和扫描方向。这几个参数的配置在stm32f0xx_ad.H中使用一个结构体进行了说:

[c]

typedef struct
{
uint32_t ADC_Resolution; // 配置ADC的转化分辨率
FunctionalState ADC_ContinuousConvMode; // 配置选择连续采样或单次采样
uint32_t ADC_ExternalTrigConvEdge; // ADC内部边缘触发
uint32_t ADC_ExternalTrigConv; //ADC 内部触发
uint32_t ADC_DataAlign; // 设置ADC是左对齐或者右对齐
uint32_t ADC_ScanDirection; // 设置ADC扫描方向
}ADC_InitTypeDef;

[/c]

使用中给出一组操作,基于直接存储器访问DMA的控制方式:称为为直接存储器访问模式:DMA。这种方式是为了更为有效地利用处理器和总线可用带宽而设计的。他不需要CPU的情况完成操作。下大大提高了运行效率。

DMA控制器依赖于处理器内核,但DMA不影响总线传输,因为DMA控制器总是在系统总线空闲的时候使用总线。该总线实现处理器和DMA控制器之间最优化设计,使两者之间的冲突降到最低,因此传输性能得到提高。

提供了存储单元到存储单元,外设到存储单元,存储单元到外设等转换模式。DMA为每种支持的外设功能提供专用通道,可以各自独立进行配置。其配置模式多种多样,时候于各自不同的设置要求。

采样库函数配置了DMA的几个参数:

[c]

typedef struct
{
uint32_t DMA_PeripheralBaseAddr; //配置外设地址
uint32_t DMA_MemoryBaseAddr; // 配置内存映射地址
uint32_t DMA_DIR; // 制定外设的源或者目的地
uint32_t DMA_BufferSize; // DMA缓冲设置
uint32_t DMA_PeripheralInc; //设置外设地址是否增加或不增加
uint32_t DMA_MemoryInc; // 设置内存地址是否增加或不增加
uint32_t DMA_PeripheralDataSize; //外设数据宽度设置
uint32_t DMA_MemoryDataSize; //内存数据宽度设置
uint32_t DMA_Mode; // DMA模式
uint32_t DMA_Priority; // DMA优先级
uint32_t DMA_M2M; // memory-to-memory 传输模式设置
}DMA_InitTypeDef;

[/c]

硬件准备:

硬件配置入下图所示,采用PA1作为引脚,对变阻器输入的信号进行转换:

 

软件准备:

软件采用库函数进行配置,用户需要配置编写adc.c驱动函数,工程目录如下图所示:

首先我们需要初始化AD配置,在adc.c文件中,我们编写ADC1_DMA_Init()函数,通过配置DMA通道和ADC外设,首先DMA配置如下:

[c]

/* DMA1 Channel1 Config */
DMA_DeInit(DMA1_Channel1);//选择频道
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;//设置外设地址
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&RegularConvData_Tab;//设置内存映射地址
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize =4;//缓冲为4
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_Mode = DMA_Mode_Circular;//循环模式
DMA_InitStruct.DMA_Priority = DMA_Priority_High;//高优先级
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//关内存到内存
DMA_Init(DMA1_Channel1, &DMA_InitStruct);

/* DMA1 Channel1 enable */
DMA_Cmd(DMA1_Channel1, ENABLE);//频道使能
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);//配置DMA循环模式
/* Enable ADC_DMA */
ADC_DMACmd(ADC1, ENABLE);

[/c]

然后对ADC参数进行配置:

[c]

/* 初始 ADC 配置 */
ADC_StructInit(&ADC_InitStruct);
/* 配置ADC1 在连续模式下分辨率为12 bits */
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ScanDirection = ADC_ScanDirection_Backward;
ADC_Init(ADC1, &ADC_InitStruct);
/* Convert the ADC1 Vref with 55.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_55_5Cycles);
/* ADC 刻度 */
ADC_GetCalibrationFactor(ADC1);
ADC_DMACmd(ADC1, ENABLE);
/* 使能ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* 等待ADCEN 标志 */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));

/* ADC1 定期变换 */
ADC_StartOfConversion(ADC1);

 

[/c]

写好初始化函数后,在子函数内就可以直接调用:

[c]

#include "stm32f0xx.h"
#include "adc.h"
#include "systick.h"
#include "w25x16.h"
#include "ili9328.h"
// ADC1转换的电压值通过MDA方式传到flash
extern __IO uint16_t RegularConvData_Tab;

// 局部变量,用于存从flash读到的电压值
__IO uint16_t ADC_ConvertedValueLocal;

void delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}

int main(void)
{
SystemInit();
ADC1_DMA_Init();
LCD_init(); // 液晶显示器初始化
SPI_FLASH_Init();
LCD_Clear(WHITE); // 全屏显示白色
POINT_COLOR = BLACK; // 定义笔的颜色为黑色
BACK_COLOR = WHITE; // 定义笔的背景色为白色
LCD_DrawRectage(0, 0, 320, 20, DARKBLUE); // 画一个深蓝色边框的矩形
LCD_ShowString(2,2,"实验十");
LCD_ShowString(100,2,"adc采样实验");
while(1)
{
ADC_ConvertedValueLocal= RegularConvData_Tab;
delay(0xffffee);
LCD_ShowString(20,40,"adc采样值:");
LCD_ShowNum(100,40,ADC_ConvertedValueLocal,4);
}
}

 

[/c]

实验现象:

调节滑动变阻器,AD转换后成不同的值,结果如下图所示:

 

 

 

加入微信技术交流群

技术交流,职业进阶

关注电路设计技能公众号

了解最新技术方案

加入电路城 QQ 交流群

与技术大牛交朋友

讨论 (1)

讨论区
superman1206 ·  2013-01-28