这是本文档旧的修订版!
银杏科技有限公司旗下技术文档发布平台 | |||
技术支持电话 | 0379-69926675-801 | ||
技术支持邮件 | Gingko@vip.163.com | ||
技术论坛 | http://www.eeschool.org | ||
版本 | 日期 | 作者 | 修改内容 |
---|---|---|---|
V1.0 | 2020-07-04 | gingko | 初次建立 |
(1)ADC控制寄存器(ADC_CR1和ADC_CR2)
ADC_CR1的SCAN位,该位用于设置扫描模式,由软件设置和清除,如果设置为1,则使用扫描模式,如果为0,则关闭扫描模式。在扫描模式下,由ADC_SQRx或ADC_JSQRx寄存器选中的通道被转换。如果设置了EOCIE或JEOCIE,只在最后一个通道转换完毕后才会产生EOC或JEOC中断。ADC_CR1[25:24]用于设置ADC的分辨率,详细的对应关系如图所示:
ADC_CR2寄存器的各位描述如图所示:
ADON位用于开关AD转换器,而CONT位用于设置是否进行连续转换,SWSTART 位用于开始规则通道的转换。 (2)ADC通用控制寄存器(ADC_CCR)
TSVREFE位是内部温度传感器和Vrefint通道使能位,这里我们直接设置为0。ADCPRE[1:0]用于设置ADC输入时钟分频,00~11分别对应2/4/6/8分频,MULTI[4:0]用于多重ADC模式选择。 (3)ADC采样时间寄存器(ADC_SMPR1和ADC_SMPR2),这两个寄存器用于设置通道0~18的采样时间,每个通道占用3个位。ADC_SMPR1的各位描述如图所示:
ADC_SMPR2的各位描述如下图所示:
对于每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降低ADC的转换速率。ADC的转换时间可以由以下公式计算: Tcovn=采样时间+12个周期 其中:Tcovn为总转换时间,采样时间是根据每个通道的SMP位的设置来决定的。例如,当ADCCLK=27Mhz的时候,并设置3个周期的采样时间,则得到:Tcovn=3+12=15个周期=0.55us。 (4)ADC状态寄存器(ADC_SR),该寄存器保存了ADC转换时的各种状态。该寄存器的各位描述如图所示:
这里仅介绍将要用到的是EOC位,通过判断该位来决定是否此次规则通道的AD转换已经完成,如果该位位1,则表示转换完成了,就可以从ADC_DR中读取转换结果,否则等待转换完成。 本实验中iCore4的所有电源经过电阻分压或者直接接入STM32的ADC的输出通道内,输入电流经过高端电流检测芯片ZXCT1009F输入到ADC的输入通道内,从而实现电源监控功能。
int main(void) { int i; /* MCU 配置*/ /* 重置所有外围设备,初始化Flash接口和Systick */ HAL_Init(); /* 配置系统时钟 */ SystemClock_Config(); /* 初始化所有已配置的外围就设备 */ MX_GPIO_Init(); MX_ADC3_Init(); MX_USART6_UART_Init(); usart6.initialize(115200); LED_GREEN_ON; usart6.printf("\x0c"); //清屏 usart6.printf("\033[1;32;40m"); //设置终端字体为绿色 usart6.printf(" Hello, I am iCore4!\r\n"); /* 无限循环 */ while (1) { LED_GREEN_ON; HAL_Delay(500); LED_GREEN_OFF; //读取ADC for(i = 0;i < 5;i ++){ my_adc.read(i); } //打印系统供电电压 usart6.printf(" "); usart6.printf("[I] %3.0fmA , ",my_adc.value[0] / 2* 1000.); usart6.printf("[V] %4.2fV, ",my_adc.value[1] * 6.); usart6.printf("[3.3V] %4.2fV, ",my_adc.value[2] * 2.); usart6.printf("[2.5V] %4.2fV,",my_adc.value[3] * 2.); usart6.printf("[1.2V] %4.2fV\r",my_adc.value[4]); } }
typedef struct { ADC_TypeDef *Instance; //ADC1/ADC2/ADC3 ADC_InitTypeDef Init; //初始化结构体变量 __IO uint32_t NbrOfCurrentConversionRank;//当前转换序列 DMA_HandleTypeDef *DMA_Handle; //DMA方式使用 HAL_LockTypeDef Lock; //ADC锁定对象 __IO uint32_t State; //ADC通讯状态 __IO uint32_t ErrorCode; //ADC错误代码 }ADC_HandleTypeDef;
typedef struct { uint32_t ClockPrescaler; //时钟分频系数2/4/6/8分频 uint32_t Resolution; //分辨率12/10/8/6 位 uint32_t DataAlign; //对齐方式,左对齐还是右对齐 uint32_t ScanConvMode; //扫描模式 uint32_t EOCSelection; //EOC标志是否设置 uint32_t ContinuousConvMode; //开启连续转换模式或者单次转换模式 uint32_t NbrOfConversion; //规则序列中有多少个转换 uint32_t DiscontinuousConvMode; //不连续采样模式 uint32_t NbrOfDiscConversion; //不连续采样通道数 uint32_t ExternalTrigConv; //外部触发方式 uint32_t ExternalTrigConvEdge; //外部触发边沿 uint32_t DMAContinuousRequests; //开启 DMA 请求连续模式或者单独模式 }ADC_InitTypeDef;
void MX_ADC3_Init(void) { ADC_ChannelConfTypeDef sConfig; /**配置ADC的全局功能(时钟,分辨率,数据对齐和转换次数)*/ hadc3.Instance = ADC3; hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;//4分频 hadc3.Init.Resolution = ADC_RESOLUTION_12B;// 12 位模式 hadc3.Init.ScanConvMode = DISABLE; //非扫描模式 hadc3.Init.ContinuousConvMode = DISABLE; //关闭连续转换 hadc3.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式 hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发 hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发 hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐 hadc3.Init.NbrOfConversion = 1; //1 个转换在规则序列中 hadc3.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求 hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //EOC中断 if (HAL_ADC_Init(&hadc3) != HAL_OK) //初始化ADC3 { _Error_Handler(__FILE__, __LINE__); } /*为选定的ADC常规通道配置其在定序器中的相应等级及其采样时间 */ sConfig.Channel = ADC_CHANNEL_7; //通道 sConfig.Rank = 1; //第1个序列,序列1 sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; //采样时间 if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK) //通道配置 { _Error_Handler(__FILE__, __LINE__); } }
int read_adc(int channel) { int i,k; unsigned long int temp[20] = {0}; unsigned long int value; unsigned short int data[100]; ADC_ChannelConfTypeDef channel_config; unsigned char channel_remap[5] = {ADC_CHANNEL_7,ADC_CHANNEL_12,ADC_CHANNEL_4,ADC_CHANNEL_5,ADC_CHANNEL_6}; channel_config.Channel = channel_remap[channel]; channel_config.Offset = 0; channel_config.Rank = 1; channel_config.SamplingTime = ADC_SAMPLETIME_480CYCLES; for(k = 0;k < 20;k++){ for(i = 0;i < 100;i ++){ HAL_ADC_ConfigChannel(&hadc3,&channel_config); HAL_ADC_Start(&hadc3); while(!__HAL_ADC_GET_FLAG(&hadc3,ADC_FLAG_EOC)); data[i] = HAL_ADC_GetValue(&hadc3); } sort(data,100); for(i = 40;i < 60;i++){ temp[k] += data[i]; } temp[k] = temp[k] / 20; } value = 0; for(k = 0;k < 20;k++){//获取平均值,用来提高准确度 value += temp[k]; } value /= 20; my_adc.value[channel] = value * ADC_REF / 4096; return value; }