赞
踩
本内容基于江协科技STM32视频学习之后整理而得。
在ADC初始化的结构体里,会有两个参数:参1是选择单次转换还是连续转换,参2是选择扫描模式还是非扫描模式。
它在一次转换结束后,不会停止,而是立刻开始下一轮的转换,然后一直持续下去。因此只需最开始触发一次,之后就可以一直转换。优点是开始转换之后不需要等待一段时间,想要读AD值的时候,直接从数据寄存器取就是了。
每触发一次,转换结束后,就会停下来,下次转换就得再触发才能开始。初始化结构体中还会有个参数:通道数目,若为7,就是在每次触发之后,依次对前7个位置进行AD转换,转换结果都放在数据寄存器里。为了防止数据被覆盖,就需要用DMA及时将数据挪走。7个通道转换完成之后,产生EOC信号,转换结束。然后再触发下一次,就又开始新一轮的转换。
一次转换完成后,立刻开始下一次的转换。
在扫描模式的情况下,还有一种模式:间断模式,在扫描的过程中,每隔几个转换,就暂停一次,需要再次触发,才能继续。
类型:外部引脚/来自片上定时器的内部信号,具体是引脚还是定时器,需要用AFIO重映射来确定。
软件控制位:软件触发
触发信号的选择可以通过设置右边的寄存器来完成。也可以使用库函数实现。
ADC是12位的,其转换结果就是一个12位的数据。但数据寄存器是16位的,所以存在数据对齐的问题
// 配置ADCCLK分频器 void RCC_ADCCLKConfig(uint32_t RCC_PCLK2); // DeInit恢复缺省配置、Init初始化、StructInit结构体初始化 void ADC_DeInit(ADC_TypeDef* ADCx); void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct); void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct); // 给ADC上电的,即开关控制 void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); // 开启DMA输出信号 void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState); // 中断输出控制,用于控制某个中断,能不能通往NVIC void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState); // 复位校准、获取复位校准状态 void ADC_ResetCalibration(ADC_TypeDef* ADCx); FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx); // 开始校准、获取开始校准状态 void ADC_StartCalibration(ADC_TypeDef* ADCx); FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx); // ADC软件开始转换控制,用于软件触发的函数 void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); // ADC获取软件开始转换状态 FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx); // 判断转换是否结束。获取标志位状态,参数给EOC的标志位,判断EOC标志位是不是置1了 FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); // 配置间断模式,函数1:每隔几个通道间断一次;函数2:是不是启用间断模式 void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number); void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); // ADC规则组通道配置,给序列的每个位置填写指定的通道 void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); // ADC 外部触发转换控制,就是是否允许外部触发转换 void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); // ADC换取转换值。就是获取AD转换的数据寄存器,读取转换结果使用该函数 uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx); // ADC获取双模式转换值,是ADC模式读取转换结果的函数 uint32_t ADC_GetDualModeConversionValue(void); // 对ADC注入组进行配置 void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv); void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx); void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length); void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset); uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel); // 对模拟看门狗进行配置,函数1:是否启动看门狗;函数2:配置高低阈值;函数3:配置看门的通道 void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog); void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold); void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel); // ADC温度传感器、内部参考电压控制,用于开启内部的两个通道 void ADC_TempSensorVrefintCmd(FunctionalState NewState); // 获取中断状态、清除中断挂起位 FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT); void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
实现功能:接一个电位器,即滑动变阻器,用该电位器产生一个0~3.3V连续变化的模拟电压信号,接到STM32的PA0口上,之后用STM32内部的ADC读取电压数据,显示在屏幕上。屏幕上第一行显示的是AD转换后的原始数据,第二行是经过处理后实际的电压值。往左拧,AD值减小,电压值也减小,AD值最小为0,对应的电压就是0V,往右拧,AD值变大,对应电压值也变大。STM32的ADC是12位的,所以AD结果最大值是4095(2^12 - 1),对应的电压是3.3V。
AD.c代码:
#include "stm32f10x.h" // Device header void AD_Init(void) { /* 1. 开启RCC时钟,包括ADC和GPIO时钟,ADCCLK的分频器 2. 配置GPIO,配置为模拟输入模式 3. 配置多路开关,把左边的通道接入到右边的规则组列表里 4. 配置ADC转换器,采用库函数结构体:包括AD转换器和AD数据寄存器 5. 开关控制,调用ADC_Cmd函数,开启ADC 6. 想要软件触发转换,有函数可以触发 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 6分频=12MHz GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 模拟输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 采样时间是55.5个ADCCLK的周期 // 在规则组序列1的位置写入通道0, ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐:右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发源:软件触发 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;// 单次转换 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 非扫描模式 ADC_InitStructure.ADC_NbrOfChannel = 1; // 1个通道 ADC_Init(ADC1,&ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); // 复位校准 ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1) == SET); // 开始校准、获取开始校准状态 ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); } uint16_t AD_GetValue(void) { // 软件触发 ADC_SoftwareStartConvCmd(ADC1,ENABLE); // 判断转换结束 while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET); // 55.5 + 12.5 = 68个周期,ADCCLK = 12MHz,1/12M*68 = 5.6us,等待5.6us // ADC获取转换值 return ADC_GetConversionValue(ADC1); }
main.c代码:
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "AD.h" uint16_t ADValue; float Voltage; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1, 1, "ADValue:"); OLED_ShowString(2, 1, "Voltage:0.00V"); while(1) { ADValue = AD_GetValue(); Voltage = (float)ADValue / 4095 * 3.3; OLED_ShowNum(1, 9, ADValue, 4); OLED_ShowNum(2, 9, Voltage, 1);// 显示整数部分 OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); Delay_ms(100); } }
接了三个传感器:光敏电阻、热敏电阻、反射式红外传感器,把它们的AO(模拟电压输出端)分别接在了A1、A2、A3引脚,加上原来的电位器,总共四个输出通道,然后测出来的4个AD数据分别显示在屏幕上,AD0:电位器,往左拧,减小,往右拧增大;AD1:光敏电阻,遮挡时电阻变大,下拉作用变弱,输出电压变大,AD值增大;AD2:热敏电阻,用手热一下,温度升高,阻值变小,输出电压变小,AD值减小;AD3:反射式红外传感器,手靠近,有反光,AD值减小。
#include "stm32f10x.h" // Device header void AD_Init(void) { /* 1. 开启RCC时钟,包括ADC和GPIO时钟,ADCCLK的分频器 2. 配置GPIO,配置为模拟输入模式 3. 配置多路开关,把左边的通道接入到右边的规则组列表里 4. 配置ADC转换器,采用库函数结构体:包括AD转换器和AD数据寄存器 5. 开关控制,调用ADC_Cmd函数,开启ADC 6. 想要软件触发转换,有函数可以触发 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 6分频 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 模拟输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐:右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发源:软件触发 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;// 单次转换 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 非扫描模式 ADC_InitStructure.ADC_NbrOfChannel = 1; // 1个通道 ADC_Init(ADC1,&ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); // 复位校准 ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1) == SET); // 开始校准、获取开始校准状态 ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); } uint16_t AD_GetValue(uint8_t ADC_Channel) { /* 调用该函数时,只要先指定通道, 返回值就是我们指定通道的结果. 通道为 0、1、2、3 */ // 采样时间是55.5个ADCCLK的周期 // 通道为参数指定的通道 ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5); // 软件触发 ADC_SoftwareStartConvCmd(ADC1,ENABLE); // 判断转换结束 while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET); // 等待5.6us // ADC换取转换值 return ADC_GetConversionValue(ADC1); }
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "AD.h" uint16_t AD0, AD1, AD2, AD3; float Voltage; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1, 1, "AD0:"); OLED_ShowString(2, 1, "AD1:"); OLED_ShowString(3, 1, "AD2:"); OLED_ShowString(4, 1, "AD3:"); while(1) { AD0 = AD_GetValue(ADC_Channel_0); AD1 = AD_GetValue(ADC_Channel_1); AD2 = AD_GetValue(ADC_Channel_2); AD3 = AD_GetValue(ADC_Channel_3); OLED_ShowNum(1, 5, AD0, 4); OLED_ShowNum(2, 5, AD1, 4); OLED_ShowNum(3, 5, AD2, 4); OLED_ShowNum(4, 5, AD3, 4); Delay_ms(100); } }
类型 | 起始地址 | 存储器 | 用途 |
---|---|---|---|
ROM | 0x0800 0000 | 程序存储器Flash | 存储C语言编译后的程序代码和常量· |
0x1FFF F000 | 系统存储器 | 存储BootLoader,用于串口下载 | |
0x1FFF F800 | 选项字节 | 存储一些独立于程序代码的配置参数 | |
RAM | 0x2000 0000 | 运行内存SRAM | 存储运行过程中的临时变量 |
0x4000 0000 | 外设寄存器 | 存储各个外设的配置参数 | |
0xE000 0000 | 内核外设寄存器 | 存储内核各个外设的配置参数 |
主要包括:CPU和存储器
默认优先级是通道号越小,优先级越高。也可以在程序中配置优先级。
// ADC1_BASE是ADC1的基地址,基地址就是起始地址,即4001 2400 #define ADC1 ((ADC_TypeDef *) ADC1_BASE) #define ADC1_BASE (APB2PERIPH_BASE + 0x2400) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */ typedef struct { __IO uint32_t SR; __IO uint32_t CR1; __IO uint32_t CR2; __IO uint32_t SMPR1; __IO uint32_t SMPR2; __IO uint32_t JOFR1; __IO uint32_t JOFR2; __IO uint32_t JOFR3; __IO uint32_t JOFR4; __IO uint32_t HTR; __IO uint32_t LTR; __IO uint32_t SQR1; __IO uint32_t SQR2; __IO uint32_t SQR3; __IO uint32_t JSQR; __IO uint32_t JDR1; __IO uint32_t JDR2; __IO uint32_t JDR3; __IO uint32_t JDR4; __IO uint32_t DR; } ADC_TypeDef; ADC1->DR // ADC1是结构体指针,指向的是ADC1外设的起始地址, // 访问结构体成员,相当于是加一个地址偏移。 // 起始地址 + 偏移,就是指定的寄存器
// 恢复缺省配置 void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx); // 初始化 void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct); // 结构体初始化 void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct); // 使能 void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState); // 中断输出使能 void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState); // DMA设置当前数据寄存器,给传输计数器写数据的 void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); // DMA获取当前数据寄存器,返回传输计数器的值 uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx); // 获取标志位状态 FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG); // 清除标志位 void DMA_ClearFlag(uint32_t DMAy_FLAG); // 获取中断状态 ITStatus DMA_GetITStatus(uint32_t DMAy_IT); // 清除中断挂起位 void DMA_ClearITPendingBit(uint32_t DMAy_IT);
使用DMA进行存储器到存储器的数据转运,把一个数组(源数组)的数据转运到另一个数组(目的数组)中。采用软件触发。
在OLED中显示源数组DataA 、地址及数据,目的数组DataB、地址及数据。
#include "stm32f10x.h" // Device header uint16_t MyDMA_Size; void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint32_t Size) { /* 1. RCC开启DMA的时钟 2. 调用DMA_Init,初始化参数:外设和存储器站点的 起始地址、数据宽度、地址是否自增、方向、 传输计数器、是否需要自动重装、选择触发源 3. 开关控制,DMA_Cmd 4. 如果是硬件触发,在对应的外设调用一下xxx_DMACmd, 开启一下触发信号的输出 5. 如果需要DMA的中断,调用DMA_ITConfig,开启中断输出, 再在NVIC里,配置相应的中断通道,写中断函数 6. 如果转运完成,传输计数器清0了,若再想给传输计数器赋值的话, 就DMA失能、写传输计数器、DMA使能。 */ // DMA是AHB总线的设备,需要开启AHB时钟 MyDMA_Size = Size; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA; // 外设站点的起始地址 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设站点的数据宽度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable ; // 外设站点的是否自增 DMA_InitStructure.DMA_MemoryBaseAddr = AddrB; // 存储器站点的起始地址 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 存储器站点的数据宽度 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 存储器站点的是否自增 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 传输方向 DMA_InitStructure.DMA_BufferSize = Size; // 缓存区大小,即传输计数器 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 传输模式,就是是否使用自动重装 DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; // 选择是否是存储器到存储器,即选择软件触发还是硬件触发 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 优先级 DMA_Init(DMA1_Channel1, &DMA_InitStructure); /* DMA转运有三个条件: 1. 传输计数器大于0 2. 触发源有触发信号 3. DMA使能 */ DMA_Cmd(DMA1_Channel1, DISABLE); } // DMA传输函数,调用依次这个函数,就再次启动一次DMA转运 void MyDMA_Transfer(void) { // 重新给传输计数器赋值,先使DMA失能 DMA_Cmd(DMA1_Channel1, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size); DMA_Cmd(DMA1_Channel1, ENABLE); // 等待转运完成 while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); DMA_ClearFlag(DMA1_FLAG_TC1); }
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "MyDMA.h" /* uint8_t bb = 0x66; // 存储在SRAM中 const uint8_t aa = 0x66; 存储在Flash中,const定义的变量是常量,值不能更改 Flash是只读不能写入,因此const与Flash对应 */ uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};// 源端数组 uint8_t DataB[] = {0, 0, 0, 0};// 目标数组 int main(void) { OLED_Init(); // 把DataA数组的数据转运到DataB里 MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4); OLED_ShowString(1, 1, "DataA"); OLED_ShowString(3, 1, "DataB"); OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);// 显示DataA的地址 OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8); OLED_ShowHexNum(2, 1, DataA[0], 2); OLED_ShowHexNum(2, 4, DataA[1], 2); OLED_ShowHexNum(2, 7, DataA[2], 2); OLED_ShowHexNum(2, 10, DataA[3], 2); OLED_ShowHexNum(4, 1, DataB[0], 2); OLED_ShowHexNum(4, 4, DataB[1], 2); OLED_ShowHexNum(4, 7, DataB[2], 2); OLED_ShowHexNum(4, 10, DataB[3], 2); while(1) { DataA[0] ++; DataA[1] ++; DataA[2] ++; DataA[3] ++; OLED_ShowHexNum(2, 1, DataA[0], 2); OLED_ShowHexNum(2, 4, DataA[1], 2); OLED_ShowHexNum(2, 7, DataA[2], 2); OLED_ShowHexNum(2, 10, DataA[3], 2); OLED_ShowHexNum(4, 1, DataB[0], 2); OLED_ShowHexNum(4, 4, DataB[1], 2); OLED_ShowHexNum(4, 7, DataB[2], 2); OLED_ShowHexNum(4, 10, DataB[3], 2); Delay_ms(1000); MyDMA_Transfer(); OLED_ShowHexNum(2, 1, DataA[0], 2); OLED_ShowHexNum(2, 4, DataA[1], 2); OLED_ShowHexNum(2, 7, DataA[2], 2); OLED_ShowHexNum(2, 10, DataA[3], 2); OLED_ShowHexNum(4, 1, DataB[0], 2); OLED_ShowHexNum(4, 4, DataB[1], 2); OLED_ShowHexNum(4, 7, DataB[2], 2); OLED_ShowHexNum(4, 10, DataB[3], 2); Delay_ms(1000); } }
使用ADC的扫描模式来实现多通道采集,然后使用DMA来进行数据转运,AD转换的数据就会自动到定义的数组里,然后用OLED显示一下。
#include "stm32f10x.h" // Device header uint16_t AD_Value[4]; void AD_Init(void) { /* 1. 开启RCC时钟,包括ADC和GPIO时钟,ADCCLK的分频器 2. 配置GPIO,配置为模拟输入模式 3. 配置多路开关,把左边的通道接入到右边的规则组列表里 4. 配置ADC转换器,采用库函数结构体:包括AD转换器和AD数据寄存器 5. 开关控制,调用ADC_Cmd函数,开启ADC 6. 想要软件触发转换,有函数可以触发 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 6分频 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 模拟输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 4个通道 ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐:右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发源:软件触发 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 单次转换,循环 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式 ADC_InitStructure.ADC_NbrOfChannel = 4; // 4个通道 ADC_Init(ADC1,&ADC_InitStructure); DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // 外设站点的起始地址 ADC DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设站点的数据宽度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable ; // 外设站点的是否自增,否 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; // 存储器站点的起始地址 SRAM DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 存储器站点的数据宽度 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 存储器站点的是否自增,是 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 传输方向 DMA_InitStructure.DMA_BufferSize = 4; // 缓存区大小,即传输计数器 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 传输模式,就是是否使用自动重装 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 选择是否是存储器到存储器,即选择硬件触发还是软件触发 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 优先级 DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_DMACmd(ADC1, ENABLE);// 开启DMA触发信号 ADC_Cmd(ADC1, ENABLE); // 复位校准 ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1) == SET); // 开始校准、获取开始校准状态 ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); ADC_SoftwareStartConvCmd(ADC1,ENABLE); } /* void AD_GetValue(void) { 调用该函数,ADC开始转换,DMA也同步进行转运, AD转换结果,依次放在这上面的AD_Value数组里, DMA_Cmd(DMA1_Channel1, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel1,4); DMA_Cmd(DMA1_Channel1, ENABLE); while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); DMA_ClearFlag(DMA1_FLAG_TC1); } */
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "AD.h" int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1, 1, "AD0:"); OLED_ShowString(2, 1, "AD1:"); OLED_ShowString(3, 1, "AD2:"); OLED_ShowString(4, 1, "AD3:"); while(1) { // AD_GetValue(); OLED_ShowNum(1, 5, AD_Value[0], 4); OLED_ShowNum(2, 5, AD_Value[1], 4); OLED_ShowNum(3, 5, AD_Value[2], 4); OLED_ShowNum(4, 5, AD_Value[3], 4); Delay_ms(100); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。