【蓝桥杯嵌入式备赛】10.拓展板数码管、ADC按键及光敏电阻

引子

进入国赛以后,拓展板也是比较重要的一部分。上面的有些东西也是第一次接触,所以借这个机会把学习的过程记录下来,帮助大家排雷。
拓展板上资源大致分为:数码管、ADC按键、光敏电阻、温度传感器、温湿度传感器、三轴加速度传感器以及两路占空比可调PWM、两路频率可调PWM(用于输入捕获)和两路ADC输入。
在这里插入图片描述

看起来很多,其实PWM和模拟信号输出部分不需要编程硬件就实现了,捕获和ADC利用之前的知识就可以。按键和光敏电阻也是基于ADC部分的原理稍作修改,这样算下来其实任务就简化了,学起来也轻松多了。

数码管

拓展板一共有三个数码管,通过74LS595移位寄存器实现的。配置完对SER(串行数据输入引脚)、SCK(串行移位时钟输入引脚)、RCK(穿行存储移位时钟输入)进行操作就能实现。

跳线帽:P3的SER、SCK、RCK与P4对应连接
在这里插入图片描述

个人理解三个引脚的用途:SER是对数码管位进行操作,可以理解成控制A-G某一段点亮或者熄灭
SCK用于移位,SCK下降沿的时候数据发生移位有效
RCK则是在下降沿将移位后的数据发送到硬件。

操作流程:
在这里插入图片描述

代码

SER、RCK、SCK分别对应PA1、PA2、PA3,配置推挽输出模式即可
预定义宏

#ifndef _SEG_H_
#define _SEG_H_

#include "stm32f10x.h"

#define SER_H	GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define SER_L	GPIO_ResetBits(GPIOA,GPIO_Pin_1)
#define RCK_H	GPIO_SetBits(GPIOA,GPIO_Pin_2)
#define RCK_L	GPIO_ResetBits(GPIOA,GPIO_Pin_2)
#define SCK_H	GPIO_SetBits(GPIOA,GPIO_Pin_3)
#define SCK_L	GPIO_ResetBits(GPIOA,GPIO_Pin_3)

void Seg_Init(void);
void Seg_Write(u8 N1,u8 N2,u8 N3);


#endif


函数

#include "seg.h"

u8 Seg7[17] = { 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00};

void Seg_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
}

void Seg_Write(u8 N1,u8 N2,u8 N3)
{
	u8 num,i;
	num = Seg7[N3];
	for(i=0;i<8;i++)
	{
		if(num&0x80)	SER_H;
		else	SER_L;
		SCK_H;
		num <<= 1;
		SCK_L;
	}
	num = Seg7[N2];
	for(i=0;i<8;i++)
	{
		if(num&0x80)	SER_H;
		else	SER_L;
		SCK_H;
		num <<= 1;
		SCK_L;
	}
	num = Seg7[N1];
	for(i=0;i<8;i++)
	{
		if(num&0x80)	SER_H;
		else	SER_L;
		SCK_H;
		num <<= 1;
		SCK_L;
	}
	RCK_H;
	RCK_L;	

}


ADC按键

ADC按键其实就是根据分压原理,可以把它看成ADC,但不能把它看成按键。其实就是只利用一个IO但是可以检测多个按键,达到节省资源的优势。(不知道国赛会不会直接拿他当按键用)

原理:每个按键按下由于分压阻值不同输入的模拟信号不同,只需要对输入模拟信号值判断在哪个范围即可。

跳线帽:P3的AKEY与P4对应连接
在这里插入图片描述

代码

预定义宏

#define AdcKey1		1
#define AdcKey2		2
#define AdcKey3		3
#define AdcKey4		4
#define AdcKey5		5
#define AdcKey6		6
#define AdcKey7		7
#define AdcKey8		8

函数

#include "adckey.h"
#include "stdio.h"
#include "lcd.h"

void ADCkey_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 2;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	
}

u16 Get_Adc(void)
{
	u16 Value;

	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5);
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);	
	while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));

	Value=ADC_GetConversionValue(ADC1);


	ADC_SoftwareStartConvCmd(ADC1, DISABLE);	

	return Value;
}

u8 Key_Compare(void)
{
	u16 value;					   
	u8 str[20];
	value =	Get_Adc();
	sprintf((char*)str,"    Key_Val : %d     ",value);
	LCD_DisplayStringLine(Line6,str);
	if(value<500)	return AdcKey1;
	else if(value>500&&value<1000)	return AdcKey2;
	else if(value>1000&&value<1500)	return AdcKey3;
	else if(value>1500&&value<2000)	return AdcKey4;
	else if(value>2000&&value<2800)	return AdcKey5;
	else if(value>2800&&value<3300)	return AdcKey6;
	else if(value>3300&&value<3800)	return AdcKey7; 
	else	return AdcKey8;
	
}

光敏电阻

这个也挺简单的,所以和上面两个放一块儿。光敏电阻就算随着光强增加阻值变小,它接在一个分压电路上。阻值变化分压就会相应变化,再通过ADC采集它的数值。光敏电阻有两种输出,一个模拟量一个开关量。开关量其实就算通过一个比较器,同相输入端是采集的模拟量,反向端是PR7的滑动电阻设置的一个可变的数值进行比较,输出0/1。

跳线帽:P5的TRD0和TRA0与P4对应连接

更详细原理可以参考这个:

https://blog.csdn.net/weixin_44236302/article/details/104818618?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

在这里插入图片描述

代码

#include "tr.h"
#include "stdio.h"
#include "lcd.h"

void Tr_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));	
}

void Get_TrVal(void)
{
	u16 Value;
	u8 str[20];

	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_55Cycles5);
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);	
	while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));

	Value=ADC_GetConversionValue(ADC1);

	ADC_SoftwareStartConvCmd(ADC1, DISABLE);

	sprintf((char*)str,"    TrAo_Val : %.2f     ",(float)3.3*Value/4095);
	LCD_DisplayStringLine(Line3,str);

	if(TrDo==1)
		sprintf((char*)str,"    TrDo : High    ");
	else
		sprintf((char*)str,"    TrDo : Low    ");
	LCD_DisplayStringLine(Line5,str);


}

最后补充

ADC按键从代码其实也可以看出我把ADC的值显示出来了,这样大家按下每个按键大概就能自己划定检测按键的范围了。相比直接把区间背下来,这样就算换了别的板子也更稳定,调试起来也很快。

还有一个问题,光敏电阻以后和ADC按键同时使用(通道4和通道5),是分别进行初始化的。但是出现了两路数据显示颠倒的问题,光敏电阻值显示的ADC按键值,按键按下改变的是光敏电阻显示的值。但如果两路单独运行其中一路即恢复正常。

解决办法:两路在ADC在同一函数初始化
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值