TM32F767xx系列有3个ADC,这些ADC可以独立使用,也可以使用双重/三重模式(提高采样率)。STM32F767的ADC是12位逐次逼近型的模拟数字转换器。它有19个通道,可测量16个外部源、2个内部源和Vbat通道的信号。我使用的是STM32F767IGT6。
不要让ADC的时钟超过36M,否则将导致结果准确度下降。STM32F767的ADC最大工作频率是36Mhz,而ADC时钟(ADCCLK)来自APB2,APB2频率一般是108Mhz,我们设置ADCPRE=01,即4分频,这样得到ADCCLK频率为27Mhz
ADC的转换时间: 总转换时间(Tcovn)=采样时间+12个周期
例如,当ADCCLK=27Mhz的时候,并设置3个周期的采样时间,则得到:Tcovn=3+12=15个周期=0.55us。
stm32f767的采样时间周期可以在stm32f7xx_hal_adc.h中选择,可以选择3~480个周期的采样时间。如下图所示:
ADC里面用到的寄存器有很多,常用的有以下几个,具体使用方法就不一一介绍了
DMA 全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。
DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。
STM32最多有2个DMA控制器,2个DMA控制器总共有16个数据流(每个控制器8个)。每个DMA控制器都用于管理一个或者多个外设的存储器访问请求。
我将它们都配置在了adc.c文件中,代码如下所示:
#include "adc.h"
#include "delay.h"
#include "usart.h"
#include "sdram.h"
#include "led.h"
#include "lcd.h"
#define M 8 //定义M
#define N 4
u16 value[N][M];
uint32_t ADC_ConvertedValueRead[4];
uint32_t ADC_ConvertedValue[4];
ADC_HandleTypeDef ADC1_Handler; //ADC句柄
DMA_HandleTypeDef ADC1TxDMA_Handler; //DMA句柄
//初始化ADC
void MY_ADC_Init(void)
{
ADC_ChannelConfTypeDef ADC1_ChanConf;
//GPIO初始化
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); //开启GPIOC时钟
GPIO_Initure.Pin=GPIO_PIN_5|GPIO_PIN_7; //PA5
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5; //|GPIO_PIN_5;
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
//ADC1功能配置
ADC1_Handler.Instance=ADC1;
ADC1_Handler.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
ADC1_Handler.Init.Resolution=ADC_RESOLUTION_12B; //12位模式
ADC1_Handler.Init.DataAlign=ADC_DATAALIGN_RIGHT; //右对齐
ADC1_Handler.Init.ScanConvMode=ENABLE; //扫描模式,扫描模式用于多通道采集
ADC1_Handler.Init.EOCSelection=DISABLE; //关闭EOC中断
ADC1_Handler.Init.ContinuousConvMode=ENABLE; //开启连续转换模式,即不停地进行ADC转换
ADC1_Handler.Init.NbrOfConversion=4; //规则序列中有4个转换
ADC1_Handler.Init.DiscontinuousConvMode=DISABLE; //禁止不连续采样模式
ADC1_Handler.Init.NbrOfDiscConversion=0; //不连续采样通道数为0
ADC1_Handler.Init.ExternalTrigConv=ADC_SOFTWARE_START; //软件触发
ADC1_Handler.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发
ADC1_Handler.Init.DMAContinuousRequests=ENABLE; //开启DMA请求
ADC1_Handler.DMA_Handle=&ADC1TxDMA_Handler;
HAL_ADC_Init(&ADC1_Handler); //初始化
//采样通道、顺序配置
ADC1_ChanConf.Channel=ADC_CHANNEL_7; //通道
ADC1_ChanConf.Rank=1; //序列
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset=0;
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
ADC1_ChanConf.Channel=ADC_CHANNEL_14; //通道
ADC1_ChanConf.Rank=2; //序列
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset=0;
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
ADC1_ChanConf.Channel=ADC_CHANNEL_15; //通道
ADC1_ChanConf.Rank=3; //序列
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset=0;
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
ADC1_ChanConf.Channel=ADC_CHANNEL_5; //通道
ADC1_ChanConf.Rank=4; //序列
ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC1_ChanConf.Offset=0;
HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
}
//初始化DMA
void DMA_Config(void)
{
__HAL_RCC_DMA2_CLK_ENABLE(); //DMA2时钟使能
ADC1TxDMA_Handler.Instance=DMA2_Stream0; //数据流选择
ADC1TxDMA_Handler.Init.Channel=DMA_CHANNEL_0; //通道选择
ADC1TxDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY; //外设到存储器
ADC1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式
ADC1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式
ADC1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD; //外设数据长度:32位
ADC1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_WORD; //存储器数据长度:32位
ADC1TxDMA_Handler.Init.Mode=DMA_CIRCULAR; //外设流控模式 循环模式
ADC1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM; //中等优先级
ADC1TxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
ADC1TxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
ADC1TxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE; //存储器突发单次传输
ADC1TxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE; //外设突发单次传输
ADC1TxDMA_Handler.XferCpltCallback = HAL_DMA_IRQHandler;
HAL_DMA_DeInit(&ADC1TxDMA_Handler);
HAL_DMA_Init(&ADC1TxDMA_Handler);
__HAL_LINKDMA(&ADC1_Handler,DMA_Handle,ADC1TxDMA_Handler); //将DMA与ADC1联系起来(发送DMA)
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn,0,0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
void DMA2_Stream0_IRQHandler(void)
{
HAL_DMA_IRQHandler(&ADC1TxDMA_Handler);
}
//采样函数
void task_adc(void)
{
int i;
HAL_ADC_Start_DMA(&ADC1_Handler,&ADC_ConvertedValueRead[0],4);
for(i=0; i
注意 :STM32767在使用时一定要注意Cache的问题
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
/********* 扩展变量 **********/
extern ADC_HandleTypeDef ADC1_Handler; //ADC句柄
extern DMA_HandleTypeDef ADC1TxDMA_Handler; //DMA句柄
/********* 函数声明**********/
void MY_ADC_Init(void); //ADC通道初始化
void DMA_Config(void);
void task_adc(void);
#endif
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
#include "adc.h"
extern uint32_t ADC_ConvertedValueRead[4];
int main(void)
{
Cache_Enable(); //打开L1-Cache
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz
delay_init(216); //延时初始化
uart_init(115200); //串口初始化
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
SDRAM_Init(); //初始化SDRAM
LCD_Init(); //LCD初始化
MY_ADC_Init(); //初始化ADC1
DMA_Config();
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");
LCD_ShowString(30,70,200,16,16,"ADC TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2019/4/18");
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(30,130,200,16,16,"ADC1_PA7_VAL:");
LCD_ShowString(30,150,200,16,16,"ADC1_PC4_VAL:");
LCD_ShowString(30,170,200,16,16,"ADC1_PC5_VAL:");
LCD_ShowString(30,190,200,16,16,"ADC1_PA5_VAL:");
printf("采样开始\r\n ");
task_adc();
printf("采样结束\r\n ");
while(1);
}
以上代码我亲测有效,当然,如果有什么问题,欢迎交流讨论。