蓝桥杯嵌入式国赛知识点

一、数码管

  • SEG数码管显示(PA1、PA2、PA3),
    PA1——SER串行输入数据,PA2——RCK输出锁存时钟,PA3——SCK移位寄存器时钟上升
  • 初始化:GPIO模式(PA1、PA2、PA3):GPIO_Mode_Out_PP推挽输出
    时钟:GPIOA
  • 共阴极显示,即:高电平时,发光二极管点亮,(0:灭,1:亮)

蓝桥杯嵌入式国赛知识点

  • 每个数码管的8位二进制排序位【dp、g、f、e、d、c、b、a】
    因为串行输入时,是从前往后输出,接受时,会将数据从后往前保存,即先接受dp位,将dp保存到最后面
    因此,在设置输出到数码管的字段时,应该从后往前设置
    关于串行输入是怎么操作的,不介绍,自行百度
    因此,用数码管表示16进制的0~ F,使用如下数组,依次表示0~F以及全部熄灭
    uc8 Seg7[17] = { 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; 
    

使用代码如下:
(需记忆,是固定的)

void SEG_DisplayValue(u8 Bit1,  u8 Bit2, u8 Bit3)//参数表示想让三个数码管显示的十六进制数
{
	u8 i = 0;	//做循环使用
	u8 code_tmp = 0;//标识数码管点亮时对应的十六进制数

	code_tmp = Seg7[Bit3];//设置第三个译码管
	for(i=0;i<8;i++){
	//注意,这里使用的是串行输入SER,即每次只输入一位数据,也就是把8位二进制的首位给输入到数码管当中,因此,需要连续输入8次
	//这里的输入指从PC机写入的数据输入到开发板
		if(code_tmp & 0x80 ){//0x80二进制为1000 0000,即每次循环将code_tmp的首位与1作逻辑与
		//
			GPIO_SetBits(GPIOA,GPIO_Pin_1);//SER_H;如果code_tmp首位为1,那么,串行输入的SER_H值置为1
		}else{
			GPIO_ResetBits(GPIOA,GPIO_Pin_1);//SER_L;//如果code_tmp首位为0,那么,串行输入的SER_H值置为0
		}
		GPIO_SetBits(GPIOA,GPIO_Pin_3);//SCK_H;//移位寄存器打开
		code_tmp = code_tmp << 1;   //让code_tmp 左移一位,准备判断下一位的串行输入的数据
		//每次左移一位,即将下一位串行输出的数据放到首位
		GPIO_ResetBits(GPIOA,GPIO_Pin_3);//SCK_L;//移位后,重新把移位寄存器关闭,防止出现错误
	}
	//其他数码管的操作同上
	code_tmp = Seg7[Bit2];//设置第二个译码管
	for(i=0;i<8;i++){

		if(code_tmp & 0x80){
			GPIO_SetBits(GPIOA,GPIO_Pin_1);//SER_H;
		}else{
			GPIO_ResetBits(GPIOA,GPIO_Pin_1);//SER_L;
		}
		GPIO_SetBits(GPIOA,GPIO_Pin_3);//SCK_H;
		code_tmp = code_tmp << 1;   
		GPIO_ResetBits(GPIOA,GPIO_Pin_3);//SCK_L;
	}	
	
	code_tmp = Seg7[Bit1];//设置第一个译码管
	for(i=0;i<8;i++){

		if(code_tmp & 0x80){
			GPIO_SetBits(GPIOA,GPIO_Pin_1);//SER_H;
		}else{
			GPIO_ResetBits(GPIOA,GPIO_Pin_1);//SER_L;
		}
		GPIO_SetBits(GPIOA,GPIO_Pin_3);//SCK_H;
		code_tmp = code_tmp << 1;   
		GPIO_ResetBits(GPIOA,GPIO_Pin_3);//SCK_L;
	}		
	//负责输出数据的锁存,连续将输出时钟锁存打开、关闭,以保证数据不会受到其他程序段的影响
	//当三个数码管的数据都已经输入完成,那么把数据锁存起来
	GPIO_SetBits(GPIOA,GPIO_Pin_2);//RCLK_H;
	GPIO_ResetBits(GPIOA,GPIO_Pin_2);//RCLK_L;
}

二、BUTTON(ADC)

  • 需要盖帽PA5—AKEY上,此时,按扩展板上的8个按钮,会输出相应的ADC值,ADC同样是12位的
  • 初始化:GPIO模式GPIO_Mode_AIN(模拟输入)、
    ADC(ADC1_IN5,查看芯片手册,可以发现,PA5对应的是ADC1的通道5)
    NVIC:配置优先级
    时钟:GPIOA、ADC1
  • 其他函数调用
    	RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟(只有这一个需要去"stm32f10x_rcc.h"里面找)
    	ADC_Cmd(ADC1,ENABLE);//打开ADC
    	ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //中断配置
    	
    	ADC_ResetCalibration(ADC1);//校准ADC
    	ADC_StartCalibration(ADC1);//校准ADC
    	while(ADC_GetCalibrationStatus(ADC1));//等待ADC校准完毕
    	
    	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
    	ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_13Cycles5);//规则通道配置
    
    • 判断按下的是哪一个键
    u8 Scan_Btn(void)
    {
    	u16 btn_tmp = 0;
    
    	//btn_tmp 通过中断方式读取ADC的值
    	//S1~S8按键按下后会分别产生不同的电阻分压值,通过ADC显示,其电压值大致分为14份,按下不同的键,会产生不同的电压值,每次读取到的值不一定完全相同,但一定在对应的区间当中
    	if(btn_tmp < 0x0FFF/14){
    		return 1;//按下按键S1
    	}else if((btn_tmp > 0x0FFF/14) && (btn_tmp < 0x0FFF/14*3)){
    		return 2;//按下按键S2
    	}else if((btn_tmp > 0x0FFF/14*3) && (btn_tmp < 0x0FFF/14*5)){
    		return 3;//按下按键S3
    	}else if((btn_tmp > 0x0FFF/14*5) && (btn_tmp < 0x0FFF/14*7)){
    		return 4;//按下按键S4
    	}else if((btn_tmp > 0x0FFF/14*7) && (btn_tmp < 0x0FFF/14*9)){
    		return 5;//按下按键S5
    	}else if((btn_tmp > 0x0FFF/14*9) && (btn_tmp < 0x0FFF/14*11)){
    		return 6;//按下按键S6
    	}else if((btn_tmp > 0x0FFF/14*11) && (btn_tmp < 0x0FFF/14*13)){
    		return 7;//按下按键S7
    	}else if((btn_tmp > 0x0FFF/14*13) && (btn_tmp < 0x0FDF)){
    		return 8;//按下按键S8
    	}
    	else{
    		return 0;	//error status & no key
    	}
    }
    

三、温度传感器(DS18B20)

  • 盖帽接PA6—TDQ
  • 直接使用官方提供的ds18b20.c和ds18b20.h的初始化函数ds18b20_init_x();
    并自己写一个函数,用来读取温度的值
  • 读取温度值
    s16 ds18b20_read(void)//返回值为16位数据
    {
      	u8 val1,val2;
    	s16 x = 0;	
    
      	ow_reset();
      	ow_byte_wr(OW_SKIP_ROM);
      	ow_byte_wr(DS18B20_CONVERT);
      	delay_us(750000);
    
      	ow_reset();
      	ow_byte_wr( OW_SKIP_ROM );
      	ow_byte_wr ( DS18B20_READ );
    	val1 = ow_byte_rd();//先读取低8位的温度值
      	val2 = ow_byte_rd();//再读取高8位的温度值
    
      	x = (val2<<8)+val1;//整合成16位的温度值
    	return x;
    }
    
    

四.温湿度传感器(DHT11)

  • 盖帽接PA7—HDQ
  • 直接使用官方提供的dht11.c和dht11.h的初始化函数dht11_init();
  • 直接使用温湿度读取函数dht11_read();
unsigned int dht11_read(void);
//返回一个32位的数据,数据格式为:
//8位湿度整数+8位湿度小数+8位温度整数+8位温度小数
int DHT=dht11_read();
DHT>>24;//湿度的整数部分
(DHT>>8)&0xff//温度的整数部分
//因此在显示湿度时,应该右移24位,温度应该右移8位,同时忽略前16位

五、MEMS传感器(LIS302DL)

  • 盖帽需要连接PA4—SCL、PA5—SDA
  • MEMS传感器其实和EEPROM类似,都是使用I²C,只不过EEPROM使用引脚PB7、PB6,而MEMS传感器使用引脚PA5、PA4
  • 同样的,直接使用官方提供的i2c.c、i2c.h文档,但要把
    #define I2C_PORT GPIOB
    #define SDA_Pin	GPIO_Pin_7
    #define SCL_Pin GPIO_Pin_6
    改为
    #define I2C_PORT GPIOA
    #define SDA_Pin	GPIO_Pin_5
    #define SCL_Pin GPIO_Pin_4
    
    如果要同时使用EEPROM,则把这俩个文档名字改一下即可
  • 写入LIS302DL、读取LIS302DL的函数
    uint8_t LIS302DL_Read(uint8_t adds)
    {
    	uint8_t data;
    	I2CStart();
    	I2CSendByte(0x38);
    	I2CWaitAck();
    	I2CSendByte(adds);
    	I2CWaitAck();
    
    	I2CStart();
    	I2CSendByte(0x39);
    	I2CWaitAck();
    	data=I2CReceiveByte();
    	I2CWaitAck();
    	I2CStop();
    	return data;
    
    }
    void LIS302DL_Write(uint8_t adds,uint8_t data)
    {
    	I2CStart();
    	I2CSendByte(0x38);
    	I2CWaitAck();
    	I2CSendByte(adds);
    	I2CWaitAck();
    	I2CSendByte(data);
    	I2CWaitAck();
    	I2CStop();
    }
    //可以发现,LIS302DL的接受和发送函数和EEPROM的完全相同,区别只是器件的读写地址发生了变化。
    //将0xa0、0xa1的读写EEPROM地址改为0x38、0x39的读写LIS302DL地址
    

六、光敏电阻(DO)

  • DO数字量输出接口(0和1)
  • 盖帽PA3—TRDO
  • 初始化:配置GPIO:PA3——GPIO_Mode_IPU(上拉输入)
    时钟:GPIOA
  • 模块在无光环境以及环境光线亮度达不到设定阈值时,DO端输出高电平,当外界环境光线亮度超过设定阈值时,DO端输出低电平;
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) == Bit_RESET){//GPIO_ReadInputDataBit:读取引脚输入电平
			LCD_DisplayStringLine(Line7, (u8*)"       DO:High     ");//低电平表示亮度达到阙值
		}else{
			LCD_DisplayStringLine(Line7, (u8*)"       DO:Low      ");

七、光敏电阻(AO)

  • DO模拟电压输出接口
  • 盖帽PA4—TRAO
  • 初始化:配置GPIO:PA4——GPIO_Mode_AIN(模拟输入)
    ADC(ADC1_IN4,查看芯片手册,可以发现,PA4对应的是ADC1的通道4)
    时钟:GPIOA、ADC1
    若使用中断获取光敏电阻的值,那么配置NVICADC_IT_EOC
  • 其他函数调用
    	RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟(只有这一个需要去"stm32f10x_rcc.h"里面找)
    	ADC_Cmd(ADC1,ENABLE);//打开ADC
    	ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //中断配置
    	
    	ADC_ResetCalibration(ADC1);//校准ADC
    	ADC_StartCalibration(ADC1);//校准ADC
    	while(ADC_GetCalibrationStatus(ADC1));//等待ADC校准完毕
    	
    	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
    	ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_13Cycles5);//规则通道配置
    
  • 光敏电阻根据外界光强不同,会产生不同的电阻值,光照愈强,阻值就愈低。随着光照强度的升高,电阻值迅速降低,可降低至1KΩ以下。随着电阻下降,电压不断升高。ADC读取光敏电阻两侧的电压值,来量化光强度值
    公式:tmp/(4096.-tmp)*10),其中tmp为ADC读取得到的值

八、AD采集x2

  • 盖帽PA4—AO1,PA5—AO2

  • 俩个ADC对应电位器RP5、RP6

  • 初始化:GPIO模式:PA4、PA5 :GPIO_Mode_AIN(模拟输入)、
    ADC(ADC1_IN4、ADC1_IN5,查看芯片手册,可以发现,PA4对应的是ADC1的通道4;PA5对应的是ADC1的通道5)
    时钟:GPIOA、ADC1

    ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;//因为是同时使用俩个ADC,不能在配置为独立模式;
    ADC_InitStructure.ADC_NbrOfChannel = 2;//使用规则通道的数量为2个
    //RegSimult:同步规则模式
    

    NVIC:配置优先级
    时钟:GPIOA、ADC1

  • 其他函数调用

    	RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟(只有这一个需要去"stm32f10x_rcc.h"里面找)
    	ADC_Cmd(ADC1,ENABLE);//打开ADC
    	ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //中断配置
    	
    	ADC_ResetCalibration(ADC1);//校准ADC
    	ADC_StartCalibration(ADC1);//校准ADC
    	while(ADC_GetCalibrationStatus(ADC1));//等待ADC校准完毕
    	
    	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5);
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5);//规则通道配置
    
  • 读取ADC值

u16 Get_ADCs(u8 channel)//可以使用中断方式
{
	//因为ADC1同时使用俩个通道读取,因此,每次读取ADC的值,都要选择要读取的通道
	u16 ADC_Val = 0;
	ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5);	//这一句是重点
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	ADC_Val = ADC_GetConversionValue(ADC1);
	ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
	ADC_SoftwareStartConvCmd(ADC1, DISABLE);
	return ADC_Val;
}

九、9.脉冲测量(PWM)

  • 盖帽PA6—PWM1—电位器PR1—TIM3_CH1 ,PA7—PWM2—电位器PR2—TIM3_CH2
  • 在这里插入代码片
  • 初始化:GPIO模式:PA4、PA5 :GPIO_Mode_IN_FLOATING(浮空输入)、
    TIM:配置结构体TIM_ICInitTypeDef,测量的是开发板上输入PWM,因此配置的是TIM输入结构体
    时钟:GPIOA、TIM3
    NVIC

其他函数调用

TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);//选择输入触发源:TI2:表示通道2,PF2:经过滤波器后将接到捕捉比较通道IC2;
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//选择从模式   上升沿重新初始化计数器,并且产生一个更新寄存器的信号
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);//配置从模式
TIM_Cmd(TIM3, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);

中断函数

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET){		
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
		IC2Value = TIM_GetCapture2(TIM3);
		if (IC2Value != 0){
			DutyCycle = (TIM_GetCapture1(TIM3) * 100) / IC2Value;//占空比,
			Frequency = SystemCoreClock / IC2Value;//频率,单位:HZ
		}else{
			DutyCycle = 0;
			Frequency = 0;
		}
	}
}
上一篇:DeFi终极指南【以太坊去中心化金融】


下一篇:【转】区块链:DeFi 的理论与实践