蓝桥杯扩展板使用

蓝桥杯嵌入式扩展板使用


目录

  1. 使用说明
  2. 数码管的使用
  3. ADC按键
  4. 单ADC双通道采集
  5. PWM捕获
  6. 温度传感器
  7. 温湿度传感器

使用说明

写这个的意图

  • 记录一下CubeMX的引脚和开发板跳线帽的连接。实在被这个烦的不行!
  • 把每个模块的代码固定下来,这样可以节省点时间。

我目前的情况

  • 我使用的是STM32G431RBT6

综合
主板
扩展板

  • 省一但且名次靠后。
  • 目前还在学习扩展板。

数码管使用

原理

  • 板子上的是共阴数码管,高电平点亮。
  • 控制芯片是SN74LS595N,这样就可以用三个引脚来控制三个数码管了。
  • 分别有三个我们会用到的引脚:RCLKSCKSER
  • 工作流程是这样的:
    首先我们需要把我们要输入的数据0\1放在SER引脚上,然后给SCK一个上升沿的跳变,这样SER的数据就传入移位寄存器了,我们连线进行8此这样的操作,8位数码管的数据就存在移位寄存器了,里面了,如果我们再往里面移数据,数据就会溢出这样三个74LS595串联就是24位的移位寄存器了,我们就进行24次数据存储,存储的是三个数码管的数据,这时候移位寄存器的数据还没有输出。我们给RCLK一个上升沿,数据一起输出,这样就实现了3个引脚控制三个数码管了。

备赛

  • 引脚:
网络标签芯片引脚
RCLKPA2
SCKPA3
SERPA1
  • 能够自己手写数码管驱动代码

  • 数码管显示的编码:

显示字符0123456789ABCDEFNone
段码0x3f0x060x5b0x4f0x660x6d0x7d0x070x7f0x6f0x770x7c0x390x5e0x790x710x00
  • 代码
//0、1、2、3、4、5、6、7、8、9、10(A)、11(B)、12(C)、13(D)、14(E)、15(F)
uint8_t Nixie_Number[17] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00};
void Nixie_Tube_Show(uint8_t D_1,uint8_t D_2,uint8_t D_3)//输入的是0~16的数值
{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
		uint8_t Data[3] = {D_3,D_2,D_1};
		for( uint8_t i = 0;i<3;i++ )
		{
			for( uint8_t j=0;j<8;j++ )
			{
					HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
					HAL_Delay(1);
					if( Nixie_Number[Data[i]] & (0x80>>j) )
						HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
					else
						HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
					HAL_Delay(1);
					HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
					HAL_Delay(1);
			}
		}
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_Delay(1);
}

ADC按键

原理

  • 通过检测PA5:ADC_KEY的电压来确定是哪一个按键杯被按下。但是这个电压范围确定下来确实是一个麻烦事。

备赛

  • 引脚:
接线柱芯片引脚
ADC_KEYPA5
  • 要记住每个按键的ADC取值范围,我在这里首先取50次的ADC采集的值,就是直接读数据寄存器的值。然后对这50次的值排序求中位数,不知道为什么不这样捕获的值好像不是很好区分(蓝桥官方是这样写)。然后用100为基数来进行比较判断是哪一个按键按下。如果没检测到按键就说按键没有按下。
按键ADC采集寄存器值(取50次中位数)记忆编程值实际ADC采集上限范围
K102 = 2+6*0200 = 2*100
K24798 = 2+6*1800 = 8*100
K3108914 = 2+6*21400 = 14*100
K4168920 = 2+6*32000 = 20*100
K5229726 = 2+6*42600 = 20*100
K6281632 = 2+6*53200 = 32*100
K7344038 = 2+6*63800 = 38*100
K83914404000
  • 接下来我把我捕获ADC采集值后,根据上面的判断值判断是那个按键按下的代码拿上来。
#define KEY_COUNT   50//采集次数
uint8_t adc_achive_flag = 0;//用来标记是否转换完成
uint32_t adc_buf;//用来存储ACD采集值
float KEY_V[KEY_COUNT] = {0};//存取多个采集值的数组
uint16_t Read_ADC_KEY_Val(void)//读取最终读取的ADC采集值
{
	uint16_t key_val;
	for(uint8_t i =0;i<KEY_COUNT;i++)//多次采集
	{
		if( adc_achive_flag == 0 )
		{
			adc_achive_flag = 1;
			KEY_V[i] = adc_buf;
			HAL_ADC_Start_DMA(&hadc2,&adc_buf,1);
		}	
	}
	uint16_t temp;
	for(uint8_t i = 0;i<KEY_COUNT;i++)//排序
	{
		for(uint8_t j=i;j<KEY_COUNT;j++)
		{
				if( KEY_V[j]>KEY_V[j+1] )
				{
					temp = KEY_V[j];
					KEY_V[j] = KEY_V[j+1];
					KEY_V[j+1] = temp;
				}
		}
	}
	key_val = (KEY_V[KEY_COUNT/2-1]+KEY_V[KEY_COUNT/2])/2;
	return key_val;
}
uint8_t While_Scan_ADC_Key(void)
{
	uint16_t key_val = Read_ADC_KEY_Val();//获取ADC采集数据后,数据寄存器的值
	uint16_t Compare_Val = 100;//比较值计数
	if( key_val < Compare_Val*(2+6*0)  )
	{
		return  1;//按键1按下
	}
	else if( key_val < Compare_Val*(2+6*1) )
	{
		return  2;//按键1按下
	}
	else if( key_val < Compare_Val*(2+6*2) )
	{
		return  3;//按键1按下
	}	
	else if( key_val < Compare_Val*(2+6*3) )
	{
		return  4;//按键1按下
	}
	else if( key_val < Compare_Val*(2+6*4) )
	{
		return  5;//按键1按下
	}
	else if( key_val < Compare_Val*(2+6*5) )
	{
		return  6;//按键1按下
	}	
	else if( key_val < Compare_Val*(2+6*6) )
	{
		return  7;//按键1按下
	}	
	else if( key_val < Compare_Val*(40) )
	{
		return  8;//按键1按下
	}	
	else
	{
		return 0;//没有按键按下
	}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)//ADC中断回调函数
{
	if( hadc == &hadc2 )
	{
		if( adc_achive_flag == 1 )
		{
			adc_achive_flag = 0;
			HAL_ADC_Stop_DMA(&hadc2);//停止转换
		}
	}
}

单ADC双通道采集

原理

  • 原理很简单,就是和之前采集一样。由于用ADC的双通道采集功能在蓝桥的板子上会两个通道之间会有干扰,所以我们还是采用单通道的方式来采集,只是在采集不同通道时,重新配置采集通道而已。

备赛

  • 引脚
扩展板丝印原理图引脚标签芯片引脚ADC2的采集通道
RP5AO1PA4CHANNEL_17
RP6AO2PA5CHANNEL_13
  • 直接贴代码了,以后我就这样写,虽然没有DMA那样快,但是这样在这里单纯读电压值,是没有影响的。但是对于ADC按键就不要这样了,因为那个有点延迟的感觉,就是响应有点慢。
//通道枚举
typedef enum
{
	CHANNEL_17 = 17,
	CHANNEL_13 = 13
}ADC_Channel;
//根据通道直接读出ADC转换出来的寄存器值。
uint16_t Read_ADC_Channel(ADC_Channel Channel)
{
	//从adc.c里面复制
	ADC_ChannelConfTypeDef sConfig = {0};
	if( Channel == 17 )
	{
		sConfig.Channel = ADC_CHANNEL_17;
	}
	else
	{
		sConfig.Channel = ADC_CHANNEL_13;
	}
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
 {
   Error_Handler();
 }
	//开启转换,直接读值,没有影响
	HAL_ADC_Start(&hadc2);
	uint16_t val = HAL_ADC_GetValue(&hadc2);
	HAL_ADC_Stop(&hadc2);
	return val;
}

PWM捕获

原理

  • PWM捕获分两部分,一部分是频率捕获测量,一部分是脉宽捕获测量。由于还是32的片上外设,这个过了省赛就比较熟悉了,所以就只是简述一下,有这个东西。
  • 频率捕获测量:
    频率捕获使用使用的是RP3RP4,和省赛是一样的测量方法。
  • 脉宽测量:
    这个其实就是一个PWM的高电平持续时间,由于脉宽我们一般以占空比的形式表示,所以最后根据题目转换成占空比,还是直接使用。

备赛

引脚

捕获功能开发板旋钮定时器通道引脚接线柱
频率捕获1RP3tim2CHANNEL_2PA1PULS1
频率捕获2RP4tim2CHANNEL_3PA2PULS2
脉宽捕获1RP1tim3CHANNEL_1PA6PWM1
脉宽捕获1RP2tim3CHANNEL_2PA7PWM2

代码

void PWM_Init(void)//模块初始化
{
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
	__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
	__HAL_TIM_SET_COUNTER(&htim3,0);
}
uint8_t capture_flag_1 = 0;
uint32_t PWM_F_1,PWM_D_1;
uint32_t PWM_T_Count_1;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//中断回调函数
{
	if( htim == &htim3 )
	{
		if( capture_flag_1 == 0 )//频率计算
		{
			capture_flag_1 = 1;
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
			PWM_T_Count_1 = __HAL_TIM_GET_COUNTER(&htim3);
			PWM_F_1 = 80000000/80/PWM_T_Count_1;
			__HAL_TIM_SET_COUNTER(&htim3,0);
		}
		else if(capturea_flag_1 == 1)//脉宽计算
		{
			capture_flag_1 = 0;
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
			PWM_D_1 = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1)*100/PWM_T_Count_1;
		}
	} 
}

温度传感器

原理

  • 了解,国赛不给代码就在想办法。
  • 单总线时序要求非常严格,自己写代码最好看着芯片手册写,因为每种的单片机的性能不同,这样就需要我们调试信号维持时间,我记得当时我是搞的头皮发麻,因为我比较菜。

备赛

  • 引脚
接线柱芯片引脚
TDQPA6
  • 会用官方给的读寄存器函数,然后自己做数据转换,还有就是把lcd.h里面的数据类型复制到ds18b20.h,因为官方的代码要用。还有就是把延时函数定义成static要不在其他文件里面可能重定义。
  • 代码
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;
typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;
typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
typedef const uint32_t uc32;  /*!< Read Only */
typedef const uint16_t uc16;  /*!< Read Only */
typedef const uint8_t uc8;   /*!< Read Only */
static void delay(unsigned int n)
{
   while(n--);
}
float Read_Temp(void)//温度读取
{	
	//取低11位
	float T = (float)(ds18b20_read()&0x7FF)/16.0f;	
	return T;
}

温湿度传感器

原理

  • 这个应该也是给代码,不给代码就在想办法,我只要标注一下引脚

备赛

  • 引脚
接线柱芯片引脚
HDQPA7
  • 把延时函数定义成static
  • lcd.h里面的数据类型复制到ds18b20.h
  • 代码
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;
typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;
typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
typedef const uint32_t uc32;  /*!< Read Only */
typedef const uint16_t uc16;  /*!< Read Only */
typedef const uint8_t uc8;   /*!< Read Only */
static void delay(unsigned int n)
{
   while(n--);
}

上述代码地址

代码地址
提取码:2xq3

有疏忽或者错误的地方欢迎指正 最后国赛冲冲冲!!!

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值