adc.c
/*
ADC转换器三大步骤
1、采样:在时间轴上对信号数字化。也就是,按照固定的时间间隔抽取模拟信号的值,这样,采样后就可以使
一个时间连续的信息波变为在时间上取值数目有限的离散信号。
2、量化:在幅度轴上对信号数字化。也就是,用有限个幅度值近似还原原来连续变化的幅度值,把模拟信号的
连续幅度变为有限数量的有一定间隔的离散值。
3、编码:用二进制数表示每个采样的量化值(十进制数)。
四、ADC转换配置如下
1、理解电路原理图
可调电阻连接在PA5 -- ADC12_IN5
可调电阻电压范围:0~3.3V
2、开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
GPIO_Init();
3、初始化ADC_CCR寄存器。
ADC_CommonInit();
4、初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
5、使能ADC。
ADC_Cmd(ADC1, ENABLE);
6、配置规则通道参数:
ADC_RegularChannelConfig();
7、开启软件转换:ADC_SoftwareStartConv(ADC1);
8、等待转换完成,读取ADC值。
ADC_GetConversionValue(ADC1);
*/
#include "adc.h"
/*
光敏电阻连接在PA5 -- ADC12_IN5
可调电阻电压范围:0~3.3V
*/
void Adc_Init(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
//2、开启PA口时钟和ADC1时钟,设置PA1为模拟模式。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; //引脚5
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; //模拟
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空
GPIO_Init(GPIOA, &GPIO_InitStruct);
//ADC不是复用,所以不用做映射
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent; //独立模式 规则通道
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //两个采样阶段之间的延迟5个时钟
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能 通过CPU获取数据
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4; //84/4 = 21MHZ 这个值不能大于36MHZ
//3、初始化ADC_CCR寄存器。
ADC_CommonInit(&ADC_CommonInitStruct);
//4、初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; //12位模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //非扫描模式
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; //关闭连续转换
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //右对齐 12位对齐(跟中国人使用习惯有关)
ADC_InitStruct.ADC_NbrOfConversion = 1; //1个转换在规则序列中
ADC_Init(ADC1, &ADC_InitStruct);//ADC初始化
//5、使能ADC。
ADC_Cmd(ADC1, ENABLE);
//6、配置规则通道参数:通道5 第三个参数为:转换次数 ,第四个参数:两个模拟量转换时间间隔
ADC_RegularChannelConfig(ADC1, ADC_Channel_5,1,ADC_SampleTime_15Cycles);
}
u16 Get_Adc_Value(void)
{
u16 value;
//7、开启软件转换:
ADC_SoftwareStartConv(ADC1);
//8、等待转换完成,读取ADC值。
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
value = ADC_GetConversionValue(ADC1);
return value;
}
adc.h
#ifndef __ADC_H
#define __ADC_H
#include "stm32f4xx.h"
void Adc_Init(void);
u16 Get_Adc_Value(void);
#endif
main.c
/*
芯片:stm32f407vet6
引脚连接:A0--PA5
PB6--RX
PB7--TX
实现功能:通过光敏电阻调节灯的亮度
需要用到ADC(光敏电阻)、pwm(控制灯的亮度)
*/
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "pwm.h"
#include "usart.h"
#include "string.h"
//#include "hcsr04.h"
//#include "infrared.h"
//#include "iwdg.h"
//#include "rtc.h"
#include "ad.h"
#define LED0_ON GPIO_ResetBits(GPIOA,GPIO_Pin_6) //开灯
#define LED0_OFF GPIO_SetBits(GPIOA,GPIO_Pin_6) //关灯
u8 Usart_Data;
u8 rx_flag = 0; //表示串口接收标志 rx_flag = 1表示接收完成 rx_flag = 0未完成
u8 buffer[64] = {0}; //接收存储数据数组
u8 rx_buffer[64] = {0}; //接收存储数据数组
u8 rx_i,rx_count=0;
void USART1_IRQHandler(void)
{
//若是非空,则返回值为1,与RESET(0)判断,不相等则判断为真
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
/* DR读取接受到的数据*/
buffer[rx_count++] = USART_ReceiveData(USART1); //先赋值再加
if(buffer[rx_count-1] == ':') //判断是否接收到结束标志
{
for(rx_i=0; rx_i<rx_count-1; rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i]; //将数据存储在rx_buffer数组中
}
rx_flag = 1; //rx_flag = 1表示接收字符串完成
rx_count = 0;
memset(buffer, 0, sizeof(buffer));
}
//判断为真后,为下次中断做准备,则需要对中断的标志清零
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
//这是一个主函数
int main(void)
{
u16 ADC_value;
float PWM_value;
float DZ_value;
//NVIC分组 抢占优先级两位:0~3 响应优先级两位:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
Led_Init();
Usart1_Init();
Adc_Init();
Pwm_Init();
LED0_OFF;
//GPIO_ResetBits(GPIOA,GPIO_Pin_7);
while(1)
{
ADC_value = Get_Adc_Value();
printf("ADC_value = %d\n",ADC_value); //0~4000
TIM_SetCompare1(TIM3,ADC_value);//ADC_value的数值决定灯的亮度
//LED0_ON;
delay_s(1);
}
return 0;
}
README
在这里使用了adc、pwm和串口。这里串口用的代码就是上几篇的usart.c和usart.h,没有改动。
经过实验,这样就能实现。在这里,串口直接使用printf,就会输出光度值。
但在一些教程 ,好像需要串口通过重定向标准输出流(stdio.h库中的标准输出函数)到USART1串口。
这样,在调用printf()函数时,输出的数据就会自动发送到USART1串口上。这通常需要在编译器或者工程设置中进行配置,以确保printf()函数正确地发送数据到串口。
怎么printf重定向?有待研究。