11-STM32F1 ADC

STM32F1 ADC


STM32 拥有 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=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);	//配置完成后一定要记得使能串口
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值