11-STM32F1 ADC

STM32F1 ADCSTM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用,也可以使用双重模式(提高采样率)。 STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。STM32F103 系列最少都拥有 2 个 ADC,我们选择的 STM32F103ZET 包含有 3 个 ADC。STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。 其实ADC配合DMA是比较好用的,这里只是为了总结ADC的原理所以没有使用DMA。那个注入通道感觉一般情况用不到,除非是高速转换才用到,所以暂时不纠结,本实验是用软件触发ADC转换,触发一次就转换一次,步骤如下; 步骤; 1;IO配置为模拟输入 2;打开ADC时钟 3;对ADC时钟进行分频 4;ADC是否需要连续转换 5;数据对齐模式,好像向右对齐比较方便计算 6;选择触发模式 7;ADC转换模式,这里是独立模式 8;选择需要转换的通道个数 9;是否进行通道轮流转换 10;使能ADC 11;复位校准ADC,并等待校准完成 12;校准ADC,并等待校准完成 13;初始化完毕,下面是开始转换了 14;选择要转换的通道 15;手动触发转换,因为上面第6步选择的是软件触发 16;等待转换完成 17;读取准转换后的ADC值 18;把ADC值转换为电压值 19;ok本实验用的是原子的精英板,转换的通道是ADC3的通道6,在PF8上。因为开发板的光敏电阻刚好在这个引脚上,所以就采集这个引脚的电压 实验目的;200ms采集一次ADC的值,然后通过串口发送到电脑上 代码如下;****************************************************************/ void init__uart1(); //串口初始化函数声明 void init_adc3() { ADC_InitTypeDef ADC_InitStruct; GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF|RCC_APB2Periph_ADC3,ENABLE); //IO时钟打开,ADC3时钟打开 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //这个是对ADC时钟分频的,ADC时钟不能超过14m, GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN; //模拟输入 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8; //PF8 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOF,&GPIO_InitStruct); ADC_DeInit(ADC3); ADC_InitStruct.ADC_ContinuousConvMode=DISABLE; //不需要连续转换 ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //数据向右对齐 ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //不需要事件触发,软件触发就好 ADC_InitStruct.ADC_Mode=ADC_Mode_Independent; //独立模式 ADC_InitStruct.ADC_NbrOfChannel=1; //只转换一个通道 ADC_InitStruct.ADC_ScanConvMode=DISABLE; //只有一个通道,所以不需要浏览转换 ADC_Init(ADC3,&ADC_InitStruct); ADC_Cmd(ADC3,ENABLE); //这是个坑,一定要使能ADC后才能校准, ADC_ResetCalibration(ADC3); //复位校准 while(ADC_GetResetCalibrationStatus(ADC3)==1); //等待复位校准完成 ADC_StartCalibration(ADC3); //校准 while(ADC_GetCalibrationStatus(ADC3)==1); //等待校准完成 }//获取ADC的电压值 float get_adc3() { float temp; ADC_RegularChannelConfig(ADC3,ADC_Channel_6,1,ADC_SampleTime_239Cycles5); //这里选择要转换的通道和转换时间 ADC_SoftwareStartConvCmd(ADC3,ENABLE); //软件触发转换 while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC)==0); //等待转换完成 temp=ADC_GetConversionValue(ADC3); //获取ADC的值 temp=3.3/4096*temp; //转换为相应的电压,默认是12位转换的吧 return temp; } int main(void) { float Voltage=0; //电压值 delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 init__uart1(); //串口1初始化 init_adc3(); while(1) { Voltage=get_adc3(); //获取ADC的电压值 printf("Voltage=%f\r\n",Voltage); //发送到电脑 delay_ms(200); //这个延时只是为了让数据输出慢点,方便观察 } } //串口中断处理函数 void USART1_IRQHandler(void) { char re_data=https://www.it610.com/article/0; //为了接收字符,还是定义为字符类型吧 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==1)//确认下是不是串口1接收中断 { re_data=USART_ReceiveData(USART1); //接收数据 USART_SendData(USART1,re_data); //发送数据 while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); //等待数据发送完 成 } //这个中断是不需要手动清除标志位的,因为读取数据后接收标志位会自动清零 }//重定义fputc函数 ,想要使用printf函数得添加这个函数 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0); //循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch; } void init__uart1() { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; // 串口IO配置,PA9,PA10 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //IO时钟打开 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; //IO方式具体看《中文手册》8.1.11章节 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING; //IO方式具体看《中文手册》8.1.11章节 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //配置串口1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //打开串口时钟 USART_InitStruct.USART_BaudRate=115200; //波特率115200 USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //无硬件流 USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; //接收和发送都使能 USART_InitStruct.USART_Parity=USART_Parity_No; //无奇偶校验 USART_InitStruct.USART_StopBits=USART_StopBits_1; //停止位1位 USART_InitStruct.USART_WordLength=USART_WordLength_8b; //数据长度8位 USART_Init(USART1,&USART_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn; //虽然知道这个参数的意思,但是还真不知道这个参数放在哪里 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能通道中断 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 NVIC_Init(&NVIC_InitStruct); //这个函数在misc.c文件里 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //打开串口中断,第二个参数是选择中断类型,这里打开的是接收中断 USART_Cmd(USART1,ENABLE); //配置完成后一定要记得使能串口 }


    推荐阅读