STM32F103RB扩展板(ADC按键+数码管)
实验功能:
使用ADC按键(8个),键入值分别代表1-8,在三个数码管上通过键入值向左移动显示
eg:
默认数码管不显示,第一次键入3,在第一个数码管上显示3
第二次键入8,第一位数码管显示8,第二位数码管显示3
第三次键入6,第一位数码管显示6,第二位数码管显示8,第三位数码管显示3
………………
涨见识了,ADC按键这波操作是真服,通过判断ADC采集到的值,来确定按键,
原理图:
每段按键加上电阻,达到分压的效果,通过ADC转换,就可以测得不同按键按下的值
计算公式
转换值=4095R/(1000+R) 此处R1的值就是1000
eg:
S1:接GND采集到的值为0
S2:4095R2/(R1+R2)
S6:按键按下采集到的值:4095*(R2+R3+R4+R5+R6)/(R1+R2+……+R6)
根据计算可以得到s1-s8按键按下采集到的值分别为:
s1 0
s2 534
s3 1149
s4 1755
s5 2367
s6 2880
s7 3507
s8 3984
对于采集到的值会存在一定的误差,这是不可避免的,通过比较中间值来处理这种也涨见识了
如:S1 ,S2采集到的值分别为 0 和 534 这时候取一个中间值267,,<267则作为按键S1按下,>267则作为按键S2按下.比较这个中间值可以避免采集值存在误差带来的问题。
所有计算结果如下:
软件设计
ADC初始化
void ADC1_Init_AKEY(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
// 运行GPIOA和ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
// PA5-IN5模拟输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化ADC1
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStruct);
// 配置通道5
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1,
ADC_SampleTime_1Cycles5);
ADC_InjectedChannelConfig(ADC1, ADC_Channel_4, 1,
ADC_SampleTime_1Cycles5);
ADC_AutoInjectedConvCmd(ADC1, ENABLE);
// 启动ADC1
ADC_Cmd(ADC1, ENABLE);
// 校准ADC1
ADC_StartCalibration(ADC1);//ADC转化校准
while(ADC_GetCalibrationStatus(ADC1));
}
unsigned int ADC1_Conv(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能软件触发
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//获取标志状态
return ADC_GetConversionValue(ADC1);//获取ADC转化值
}
unsigned int ADC1_InjeConv(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC));
ADC_ClearFlag(ADC1, ADC_FLAG_JEOC);
return ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
}
按键扫描
unsigned char AKEY_Read(void)
{
unsigned char ucAkey_Val = 0;
unsigned int uiAdc_Val = ADC1_Conv();
if(uiAdc_Val < 6000)
{
Delay_AKEY(100);
uiAdc_Val = ADC1_Conv();
if(uiAdc_Val < 4095)
{
if(uiAdc_Val > 3745)
ucAkey_Val = 8;
else if(uiAdc_Val > 3193)
ucAkey_Val = 7;
else if(uiAdc_Val > 2623)
ucAkey_Val = 6;
else if(uiAdc_Val > 2061)
ucAkey_Val = 5;
else if(uiAdc_Val > 1452)
ucAkey_Val = 4;
else if(uiAdc_Val > 841)
ucAkey_Val = 3;
else if(uiAdc_Val > 267)
ucAkey_Val = 2;
else
ucAkey_Val = 1;
}
}
return ucAkey_Val;
}
void Delay_AKEY(unsigned int ms)
{
unsigned int i, j;
for(i=0; i<ms; i++)
for(j=0; j<7992; j++); // SYSCLK = 72MHz
// for(j=0; j<1598; j++); // SYSCLK = 8MHz
}
这里注意这一段的配置
if(uiAdc_Val < 6000) 可以较大不能较小
{
Delay_AKEY(100);
uiAdc_Val = ADC1_Conv();
if(uiAdc_Val < 4095) 不能过大或过小
main.c程序
#include "key.h"
#include "led.h"
#include "lcd.h"
#include "seg.h"
#include "adc.h"
#include "usart.h"
unsigned char ucLed = 1;
unsigned char ucAkey_Long;
unsigned long ulTick_ms, ulAkey_Time;
unsigned int key_number;//LCD显示
unsigned char pucStr[21];
unsigned char ucDot; //小数点
int seg[3]={17,17,17};
void LCD_Proc(void);
void AKEY_Proc(void);
void ledAll_turn (void);
void seg_left(void);
int main(void)
{
SysTick_Config(72000); // 定时1ms(HCLK = 72MHz)
LED_Init();
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
ADC1_Init_AKEY();
SEG_Init();
while(1)
{
AKEY_Proc();
LCD_Proc();
SEG_Disp(seg[2],seg[1],seg[0],ucDot);
}
}
unsigned char ucAkey_Val;
int jishu=0;
void AKEY_Proc(void)
{
ucAkey_Val = AKEY_Read();
if(ucAkey_Val != ucAkey_Long)
{
ucAkey_Long = ucAkey_Val;
ulAkey_Time = ulTick_ms;
}
else
ucAkey_Val = 0;
if(ucAkey_Val)
{
key_number=ucAkey_Val;
ledAll_turn();
seg_left();
}
}
//函数功能:数码管数值每按一次左移一位
void seg_left(void)
{
ucDot++;
if(seg[0])
{
seg[2]=seg[1];
seg[1]=seg[0];
}
seg[0]=ucAkey_Val;
}
//函数功能:LCD上显示键入值
void LCD_Proc(void)
{ //注:使用sprintf需要加"usart.h"
sprintf((char*)pucStr, " key number:%02d ", key_number);
LCD_DisplayStringLine(Line4, pucStr);
}
//函数功能:控制所有LED翻转
int ledall[8]={1 ,2 ,4, 8, 16, 32, 64 ,128 };
int i;
void ledAll_turn (void)
{
i=ucAkey_Val;
if(ucLed == ledall[i-1])
ucLed=0;
else
ucLed = ledall[i-1];
LED_Disp(ucLed);
}
// SysTick中断处理程序
void SysTick_Handler(void)
{
ulTick_ms++;
}
完整工程下载>>GitHub
选择第7个工程