- 首页 > it技术 > >
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);
//配置完成后一定要记得使能串口
}
推荐阅读