第十二届蓝桥杯嵌入式备考

第十二届蓝桥杯嵌入式备考

写在最前面

写这篇文章的目的是方便自己写代码的时候看看有没有漏掉那个步骤,所以没有特别注意介绍每个部分的原理,望见谅。
这篇文章最好用的用法是用Typora 打开,有需要可以访问https://github.com/Wurlitze/12-.git.

1.LED配置

LED的配置很简单,把PC8-15PD2配置为GPIO_Output。(PD2是锁存器,高电平开,低电平关;PC8-15对应板子上LD1-8)
LED的IO口配置

1.1GPIO HAL库函数

	HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8);  //读取PC8的电平
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);  //写PD2的电平为高
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_8);  //翻转PC8的电平

1.2LED_Disp

	void LED_Disp(uint8_t ucled)
	{
		GPIOC->ODR = ~ucled<<8;		//这里做电平翻转方便调用时高电平代表亮
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	}
1.2.1常用的LED操作
		uint8_t ucled = 4;
		LED_Disp(ucled);  //LD3亮,其他灭
		LED_Disp(~ucled); //LD3灭,其他亮
		LED_Disp(ucled ^=4); //单独让LD3翻转
		LED_Disp(ucled &= ~(1<<1)); //单独让LD2灭
		LED_Disp(ucled |= 1<<1); //单独让LD2亮

2.按键配置

PB0-2PA0配置为GPIO_Input.由于Key1PB0Key4PA0,两个的中断通道相同,所以用中断不能实现四个按键只能配置Key1-3。所以多用按键扫描的方式。按键IO口配置

2.1Key_Scan 按键扫描

	uint8_t Key_Scan(void)
	{
	    uint8_t Key_Val;
	
	    if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0))
	    {
	    	HAL_Delay(50);
	    	if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0))
	    		Key_Val = 1;
		}
	    if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1))
	    {
	    	HAL_Delay(50);
		    if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1))
		        Key_Val = 2;
		}
	    if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2))
	    {
	    	HAL_Delay(50);
		    if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2))
		        Key_Val = 3;
		}
	    if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
	    {
	    	HAL_Delay(50);		        
		    if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
		        Key_Val = 4;
		}        
		
	    return Key_Val;
	
	}

2.2 Key_Proc 按键处理函数

unsigned char Key_Long;
unsigned long ucTick_ms,KeyTick_Old;

	void Key_Proc(void)
	{
		unsigned char Key_Val;
		
		Key_Val = Key_Scan();
		
		if(Key_Val != Key_Long)
		{
			Key_Long = Key_Val;
			KeyTick_Old = ucTick_ms;
		}
		else
		{
			Key_Val = 0;
		}

		switch(Key_Val)   //单击事件处理
		{
			case 1:
	
				break;
			case 2:
				
				break;
			case 3:
	
				break;
			case 4:
	
				break;
			
		}	
		
		if(ucTick_ms - KeyTick_Old > 1000) //长按时间
			switch(Key_Long)   //长按事件处理
			{
				case 1:
		
					break;
				case 2:
					
					break;
				case 3:
		
					break;
				case 4:
		
					break;
			
			}
	

	}	

2.3按键处理常见问题汇总

1.按键1的作用一般是是页面切换,我习惯用一个布尔变量实现,然后在LCD处理函数里面写一个if判断用来实现两个页面的数据显示。每次切换都清一次屏就可以避免有些地方没有更新到带来的残留。如果某些按键要求在设置页面有效,需要在case之后写一个判断

_Bool LCD_Flag;
	//按键处理函数里面
	switch(Key_Val)
	{
		case 1:
			LCD_Flag ^= 1;
			LCD_Clear(Black);
			break;
		case 2:
			if(LCD_Flag)
			{
				
			}
			break;			

2.长按和短按case里面的内容是一样的,不需要改些什么。

3.LCD配置

  1. LCD不需要配置CubeMX,只需把lcd.c导入Src文件夹、lcd.hfonts.h导入Inc文件夹即可。在Keil里面添加.c文件,然后在main.c中引用
	#include "lcd.h" 
  1. 在main函数中初始化即可
	LCD_Init();

3.1常用LCD函数

	LCD_Clear(White);			//用白色清屏
	LCD_SetBackColor(White);	//设置背景为白色
	LCD_SetTextColor(Blue);	//设置文本为蓝色
		
	LCD_DisplayStringLine(Line0,(uint8_t *)"       Main         ");	//显示第0行
	
	//显示单个字符的时候要设置行和列,列要倒着计算最左边为320,最右边为16.
	LCD_DisplayChar(Line3,192,Time[0]/10+0x30);		//显示单个字符(数字要加0x30)
	LCD_DisplayChar(Line3,160,':');					//显示特殊符号
	
	//设置高亮
	if(j == 0)		LCD_SetTextColor(Red);
	LCD_DisplayChar(Line3,192,Time[0]/10+0x30);
	LCD_DisplayChar(Line3,176,Time[0]%10+0x30);
	LCD_SetTextColor(Blue);
	LCD_DisplayChar(Line3,160,':');

3.2LCD常见问题汇总

1.单个数字显示的时候记得转换为acsii码(如上),位置计算公式(从左到右320-16*n)。

4.ADC配置

  1. 一般使用R37,既配置PB15ADC2_IN15,其他默认即可,不用修改。
    ADC配置
  2. adc.c中添加一个getADC(); 也可以直接写在main.c里,这样就不用再添加声明了。
uint16_t getADC(void)
{
	uint16_t adc = 0;
	
	HAL_ADC_Start(&hadc2);
	adc = HAL_ADC_GetValue(&hadc2);
	
	return adc;
}
  1. adc.h中添加声明,方便外部引用该函数。
	uint16_t getADC(void);
  1. ADC处理函数
	unsigned int uiAdc_Val;
	unsigned char pucStr[21]; //方便使用sprintf函数

	void ADC_Proc(void)
	{
		float temp;	
		
		uiAdc_Val = getADC();
		temp = (float)(uiAdc_Val*3.3/4096);
		sprintf((char*)pucStr,"   V:%0.2fV          ",temp);
		LCD_DisplayStringLine(Line2, pucStr);
	}

4.1双通道ADC配置

双通道ADC一般是拓展板上测量两路ADC时用的,因为是ADC2的两个通道,所以不能使用两个ADC来测量

  1. 配置两路ADC的引脚ADC引脚配置
  2. 添加一路DMA,配置如下
    ADC的DMA配置
  3. 开启连续转换,DMA请求,把通道数改为2.ADC配置
  4. 在主函数中添加开启DMA函数,接收到的数据存放在ADC_ReBuf
uint32_t ADC_ReBuf[200],ADC_Val[2];
	
	HAL_ADC_Start_DMA(&hadc2,ADC_ReBuf,200);
  1. 处理接收到的数据,两个通道的数据是交替保存的,将得到的100的值取均值(均值滤波)。
	for(i = 0;i< 100;i++)
	{
		ADC_Val[0] += ADC_ReBuf[i*2];
		ADC_Val[1] += ADC_ReBuf[i*2+1];
	}
	
	ADC_Val[0] /= 100;
	ADC_Val[1] /= 100;
		
  1. 这里的ADC_Val就是最后得到的值(0~4096),对得到的值进行处理
	Temp1 = (float)ADC_Val[0]*3.3f/4096;
	Temp2 = (float)ADC_Val[1]*3.3f/4096;

4.1ADC常见问题总结

  1. 数字滤波(意思一下而已)
	float temp, temp1;
	unsigned int uiAdc_Val;
	unsigned char pucStr[21]; //方便使用sprintf函数

	void ADC_Proc(void)
	{
		uiAdc_Val = getADC();
		temp1 = temp;
		temp = (float)(uiAdc_Val*3.3/4096);
		
		sprintf((char*)pucStr,"   V:%0.2fV          ",temp*0.8f+temp1*0.2f);
		LCD_DisplayStringLine(Line2, pucStr);
	}

5.TIM定时器配置

定时器频率计算定时器配置

5.1PWM配置

5.1.1单PWM波配置
  1. CubeMx配置
    预分频系数Prescaler和自动重装载值ARR决定PWM波的频率,Pulse决定PWM的占空比。
    单PWM配置
  2. main函数里开启PWM通道
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
5.1.2可调频率及占空比PWM波配置
  1. 调节占空比
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,Duty_Val[1]*100); //设置比较值
  1. 调节频率
	HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_2);
	__HAL_TIM_SET_AUTORELOAD(&htim2,9999);
	__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,5000);
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
	TIM2->CNT = 0;		//清空CNT,有一次debug发现第二次配置ARR的时候CNT的值会跑飞

5.2输出捕获配置

这个模式主要用于单个定时器生成多路频率占空比都不相同的PWM波。
核心思想是通过不断更新比较值来翻转电平模拟PWM。

  • 一般不配置ARR的值,Pusle的值都可,因为后面会一直变。
    1.CubeMX配置
    在这里插入图片描述
  • 模式配置为Toggle on match
    在这里插入图片描述
  1. 重写callback函数
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
	__IO uint16_t count;
	
	if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
	{
		count =	HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);
		
		if(PA6 ^= 1)
			__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,count+Duty_Val[1]*100);
		else
			__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,count+CCR1_Val-(Duty_Val[1]*100));		
	
  	}
	
	if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
	{
		count =	HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2);

		if(PA7 ^= 1)
			__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,count+Duty_Val[2]*100);
		else
			__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,count+CCR2_Val-(Duty_Val[2]*100));			
	}

}

  1. main函数中开启中断
	HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_1);
	HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_2);

5.3输入捕获配置

  1. CubeMX配置
  • 系统时钟为80MHz,预分频系数设置为79,自动重装载值设置为0(就是这里的0xffffffff),这样一个计数值的时间为1μs。
    输入捕获配置
  • 这里设置为双边沿触发,目的是为了方便测占空比,如果只是测频率,可以设置为上升沿或下降沿触发。
  • 输入滤波器是用于稳定波形的,在外接信号发生器的时候,输入容易不稳,可以按照需求设置大小。
    在这里插入图片描述
  • 使能中断
    在这里插入图片描述
  1. 重写回调函数
  • 这里的ch2_Val数组是用来保存计数值的,因为是双边沿触发,所以可以用两个差值为2的计数值来计算频率,100000是定时器的计数频率。
  • 占空比这里没有特别深究是1的持续时间还是0的持续时间,算是一处缺陷吧,可以用交叉设置上升沿下降沿的方式来测得值为1的占空比。考虑到一般都是百分比,所以计算的时候直接乘了100。
int long ch2_Val[6], F40 = 0;
int Duty_cycle;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	ch2_Val[i++] = __HAL_TIM_GET_COUNTER(&htim2);
	
	if(i>5)
	{
		i=0;
		F40 = 1000000/(ch2_Val[4]-ch2_Val[2]);
		Duty_cycle = (ch2_Val[3]-ch2_Val[2])*100/(ch2_Val[4]-ch2_Val[2]);
		__HAL_TIM_SetCounter(&htim2,0);

	}
	
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
}

  1. main函数中开启中断
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);

5.3TIM定时器常见问题

  1. 官方给出的测频率的例子(适合单测频率),但是因为每次都赋0,会对测量精度产生一定的影响
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{

		Tim_Val = __HAL_TIM_GetCounter(&htim2);
		FRQ_Val[0] = 1000000/Tim_Val;	
		__HAL_TIM_SetCounter(&htim2,0);	
		HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
}

6.USART串口配置

  1. CubeMX配置
    需要注意,要手动配置PA9PA10USART1_TXUSART1_RX。开启中断并设置抢占优先级不为0(因为在中断处理函数中调用了延时函数,如果不设置优先级会导致程序卡死,如果没有调用延时可以配置优先级为0)。
    在这里插入图片描述
  2. 重写fputc函数(重写之后才可使用printf)
	int fputc(int c, FILE *stream)    //重写fputc函数
	{
	 /*
	    huart1是工具生成代码定义的UART1结构体,
	    如果以后要使用其他串口打印,只需要把这个结构体改成其他UART结构体。
	*/
	    HAL_UART_Transmit(&huart1, (unsigned char *)&c, 1, 1000);   
	    return 1;
	}
  1. 在中断服务函数中添加延迟,(接收多个字节的时候不需要添加)。
	void USART1_IRQHandler(void)
	{
	  /* USER CODE BEGIN USART1_IRQn 0 */
	  
	  HAL_Delay(100);   //接收多个字节的时候要注释掉
	
	  /* USER CODE END USART1_IRQn 0 */
	  HAL_UART_IRQHandler(&huart1);
	  /* USER CODE BEGIN USART1_IRQn 1 */
	
	  /* USER CODE END USART1_IRQn 1 */
	}
  1. 重写回调函数
uint8_t USART1_RX_CNT = 0, ucRxBuf;
char RxBuf[128], pucRcv[128];


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(USART1_RX_CNT >= 127)   //127+1是最大能接收到的数据长度
	{
		USART1_RX_CNT = 0;
		memset(RxBuf,0x00,sizeof(RxBuf));
		HAL_UART_Transmit(&huart1,(uint8_t *)"error",10,1000);
	}
	else	
	{
		RxBuf[USART1_RX_CNT++] = ucRxBuf;
		if((RxBuf[USART1_RX_CNT-1] == 0x0a ) && (RxBuf[USART1_RX_CNT-2] == 0x0d))
		{
			memcpy(pucRcv,RxBuf,sizeof(RxBuf));
			USART1_RX_CNT = 0;
			memset(RxBuf,0x00,sizeof(RxBuf));		
		}
		
	}

	HAL_UART_Receive_IT(&huart1,(uint8_t *)&ucRxBuf,1);

}
  1. 在main函数中添加串口中断函数
	HAL_UART_Receive_IT(&huart1,(uint8_t *)&ucRxBuf,1);
  1. 接收到的数据保存在pucRcv中,处理完接收到数据之后要对数组清零
	memset(pucRcv,0x00,sizeof(pucRcv));

6.1USART串口常见问题

  1. 在串口处理函数中经常会用到数组比较函数memcmp、数组赋值函数memset等等,这些都是C语言的函数,写在在stdio.h里,所以如果要是忘了可以在stdio.h里查,里面还有相关函数介绍。
  2. 要注意接收到数字是ascii码,要先减0X30再使用。
  • 举例如下(第六届模拟题)
		if(memcmp(RxStr,"SET:",4) == 0)
		{
			if(RxStr[4] == 0x31)
			{
				DouFrq_Val[0] = RxStr[6]-0x30;
				
				if(RxStr[9])
					DouFrq_Val[0] = 10;
			}
				

			if(RxStr[4] == 0x32)
			{
				DouFrq_Val[1] = RxStr[6]-0x30;
		
				if(RxStr[9])
					DouFrq_Val[1] = 10;
			}	
			printf("Set OK!\r\n");
			
			memset(RxStr,0x00,sizeof(RxStr));
			
			i2c_write(DouFrq_Val,0,2);
			
		}
		
  1. 处理完接收数组,记得要对数组清零。
	memset(RxStr,0x00,sizeof(RxStr));

7.EEPROM配置(i2c)

  1. CubeMX配置
    PB6PB7配置成GPIO_Output。用的是软件模拟i2c,所以不用配置i2c。但是要把i2c.c添加到Srci2c.h添加到Inc.
  2. i2c_write();和i2c_Read();
	/* E2PROM */
	//
	void i2c_read(unsigned char * pucBuf,unsigned char address,unsigned char ucNum)
	{
		
		I2CStart(); 
		I2CSendByte(0xa0);
		I2CWaitAck(); 
		
		I2CSendByte(address);
		I2CWaitAck(); 
		
		I2CStart();
		I2CSendByte(0xa1); 
		I2CWaitAck();
		
		while(ucNum--)
		{
			*pucBuf++ = I2CReceiveByte();
			if(ucNum)
				I2CSendAck();
			else
				I2CSendNotAck();
		}
	 
		I2CStop();
		
	
	}
	
	//
	void i2c_write(unsigned char * pucBuf,unsigned char address,unsigned char ucNum)
	{
		I2CStart(); 
		I2CSendByte(0xa0); 
		I2CWaitAck(); 
		
		I2CSendByte(address);	
		I2CWaitAck(); 
		
	
		
		while(ucNum--)
		{
			I2CSendByte(*pucBuf++); 
			I2CWaitAck(); 
		}
		
		
		I2CStop();
	}

  1. main函数中初始化
	I2CInit();

7.1 i2c常见问题

  1. 读写i2c示范
	unsigned char pucTh[3];
	
	i2c_read(pucTh,0,3);
	i2c_write(pucTh,0,3);

	unsigned char Time[5][3];

	i2c_read(*Time,0,15);
	i2c_write(*Time,0,15);//e2p存储

  1. 如果发现i2c读写没反应,首先就要检查是否配置PB6PB7
    在这里插入图片描述
  2. I2C的读写流程在AT24C02.pdf里面有
    i2c写i2c读

8.RTC配置

8.1使用sysTick配置

8.2使用RTC配置

  1. RTC的配置
  • 这里吗没有开启闹钟,蓝桥杯的题里面很少有用到闹钟的。
  • Data Format 是时间表示的格式 Binary data format是十进制表示,BCD data format是BCD码的形式表示。
    RTC
  1. 获取时间以及显示时间,获取时间之后一定要获取一下日期,不然程序不会往下执行。
	HAL_RTC_GetTime(&hrtc,&SysTime,RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc,&SysDates,RTC_FORMAT_BIN);
	
	sprintf((char *)pucStr,"   T:%02d:%02d:%02d   ",SysTime.Hours,SysTime.Minutes,SysTime.Seconds);	
	LCD_DisplayStringLine(Line3,pucStr);
  1. 设置时间和设置日期
HAL_StatusTypeDef settime(uint8_t hours,uint8_t mins,uint8_t secs)
{
    RTC_TimeTypeDef stime;

    stime.Hours=hours;
    stime.Minutes=mins;
    stime.Seconds=secs;
    //注意此处要用RTC_FORMAT_BIN十进制
    return HAL_RTC_SetTime(&hrtc, &stime, RTC_FORMAT_BIN);
   
}
//设置日期
HAL_StatusTypeDef setdate(uint8_t years,uint8_t mons,uint8_t dates,uint8_t weeds)
{
    RTC_DateTypeDef sdate;
    
    sdate.Year=years;
    sdate.Month=mons;
    sdate.Date=dates;
    sdate.WeekDay=weeds;
    
    return HAL_RTC_SetDate(&hrtc, &sdate, RTC_FORMAT_BIN);
}

9.数码管配置

使用数码管需要将拓展板上的P4.1~P4.3短接到P3.1 ~P3.3

  1. 配置引脚PA1~3SEG

9.1SEG显示函数

  • 这个函数直接写在mian.c里面即可
void SEG_Disp(uint8_t ucData1, uint8_t ucData2, uint8_t ucData3, uint8_t ucDot)
{
		uint8_t i;
		uint8_t code[17] = {0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00};
		unsigned long ulData = (code[ucData3] << 16) + (code[ucData2] << 8) + code[ucData1];
			
		ulData += (ucDot&1)<<23;
		ulData += (ucDot&2)<<14;
		ulData += (ucDot&4)<<5;
			
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
		
		for(i = 0; i<24 ; i++)
		{
			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
			
			if(ulData & 0x800000)
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
			else
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
			
			ulData <<= 1;
			
			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
	
		}
		
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);

}

9.2显示实例

  • 0X10代表什么也不显示,0x01代表显示0.
  /* USER CODE BEGIN 2 */
	SEG_Disp(0x10, 0x10, 0x10, 0);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		SEG_Disp(i,i+1,i+2,0);
		if(i+2 == 0x10)
			i = 0x00;
		else
			i++;
		HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

10.ADC按键配置

  1. 连接拓展板P4.5P5.5,配置PA5为一路ADC通道。
    ADC按键

10.1 Key_Scan (ADC版)

  • 这里ADC的值需要自行测量,每个按键按下对应的值会因为板子的不同而不同。
uint8_t Key_Scan(void)
{
	uint8_t ucAKey_Val;
	
	ADC_Val[0] = getADC();
	
	if(ADC_Val[0] < 3991)
	{
		HAL_Delay(100);
		if(ADC_Val[0] < 3991)
		{
			if(ADC_Val[0] > 3840)
				ucAKey_Val = 8;
			else if(ADC_Val[0] > 3080)
				ucAKey_Val = 7;
			else if(ADC_Val[0] > 2522)
				ucAKey_Val = 6;
			else if(ADC_Val[0] > 1978)
				ucAKey_Val = 5;
			else if(ADC_Val[0] > 1384)
				ucAKey_Val = 4;
			else if(ADC_Val[0] > 784)
				ucAKey_Val = 3;
			else if(ADC_Val[0] > 240)
				ucAKey_Val = 2;
			else 
				ucAKey_Val = 1;		
		}
	}	
	return ucAKey_Val;
}

10.2 Key_Proc 按键处理函数

  • 和前面的Key_Proc一样,只是判断值增加到了8.
void Key_Proc(void)
{
	uint8_t Key_Val;
	
	Key_Val = Key_Scan();
	if(Key_Val != Key_Long)
	{
		Key_Long = Key_Val;
		Tick_old = ucTick_ms;
	}
	else
		Key_Val = 0;
	
	switch(Key_Val)
	{
		case 1: 
		
			break;
		case 2:
		
			break;
		case 3:
		
			break;
		case 4:

			break;
		case 5:
					
			break;
		case 6:
					
			break;
		case 7:
				
			break;
		case 8:
				
			break;
	}
	
	if(ucTick_ms - Tick_old > 800)
	{
		switch(Key_Val)
		{
		}
		
	}
	
}

11.DHT11温湿度传感器配置

  1. 连接P4.7P3.7,配置PA7引脚。添加CHT11.csrc文件夹中,CHT11.hinc文件夹中.
    在这里插入图片描述
  2. main.c中添加以下代码。
    u8	temper ;
    u8	humi ;
    
   while(DHT11_Init())	//DHT11初始化
    {
        LCD_DisplayStringLine(Line5, (uint8_t *)"  DHT11 Error       ");
        HAL_Delay(200);
    }
  
    
    while (1)
    {
        /* USER CODE END WHILE */
        DHT11_Read_Data(&temper, & humi);		//读取温湿度值

        snprintf((char *)str, sizeof(str),  "  TH&RH:%d, %d  ", temper, humi);
        HAL_Delay(200);
        LCD_DisplayStringLine(Line6, str);
        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */

12.DS18B20温度传感器配置

  1. 连接P4.6P3.6,配置PA6引脚。添加DS18B20.csrc文件夹中,DS18B20.hinc文件夹中.在这里插入图片描述
  2. main.c中添加以下代码。
    float tem = 0.0;
    u16 read = 0;
    
    /* USER CODE BEGIN 2 */
    ds18b20_init_x();
    /* USER CODE END 2 */
    
    /* Infinite loop */
    /* USER CODE BEGIN WHILE */    
    while (1)
    {
        /* USER CODE END WHILE */
        read = (ds18b20_read() & 0x07FF);
        tem = read / 16.;
        snprintf((char *)str, sizeof(str), " Temperatrue:%2.2f"    , tem);
        LCD_DisplayStringLine(Line6, str);
        HAL_Delay(200);
    }

13.LIS302DL加速度传感器配置

  • 这个传感器其实是用来测倾斜角的,听往届的大佬说考的不多,因为需要拿板子旋转,考场会很乱。
  1. 修改i2c.c的两个引脚,数据线改为PA5,时钟线改为PA4.添加LIS302DL.csrc文件夹中,LIS302DL.hinc文件夹中(名字也有可能叫mems).

#include "i2c.h"
#define DELAY_TIME	500
/** I2C 总线接口 */
#define I2C_PORT GPIOA
#define SDA_Pin	GPIO_PIN_5
#define SCL_Pin GPIO_PIN_4

#define FAILURE 0
#define SUCCESS 1

//配置SDA信号线为输入模式
void SDA_Input_Mode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Pin =  SDA_Pin;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;

    HAL_GPIO_Init(I2C_PORT, &GPIO_InitStruct);
}

//配置SDA信号线为输出模式
void SDA_Output_Mode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Pin = SDA_Pin;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD ;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(I2C_PORT, &GPIO_InitStruct);
}
  1. 连接P2.1-P2.2 , P2.3 - P2.4;断开P4.4P4.5,配置PA4,PA5引脚.
    在这里插入图片描述

  2. main.c中添加以下代码。

s8 *ptr;
float x, y, z;

    /* USER CODE BEGIN 2 */
    LIS302DL_Config();
    /* USER CODE END 2 */

   while(LIS302DL_Check() == 0)
    {
        LCD_DisplayStringLine(Line5, (u8 *)"  MEMS STATUS: ERROR");
    }
    LCD_DisplayStringLine(Line5, (u8 *)"  MEMS STATUS: OK   ");
    while (1)
    {
        /* USER CODE END WHILE */
        ptr = Lis302DL_Output();

        x = ptr[0] * 18. / 1000;
        y = ptr[1] * 18. / 1000;
        z = ptr[2] * 18. / 1000;

        snprintf((char *)str, sizeof(str), "  X acclr:%.2fg   ", x);
        LCD_DisplayStringLine(Line6, str);
        snprintf((char *)str, sizeof(str), "  Y acclr:%.2fg   ", y);
        LCD_DisplayStringLine(Line7, str);
        snprintf((char *)str, sizeof(str), "  Z acclr:%.2fg   ", z);
        LCD_DisplayStringLine(Line8, str);
        HAL_Delay(200);
        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */

14.光敏电阻配置

  • 有两个,一个只能输出0和1(光敏电阻数字输出DO),另外一个可以输出具体的光照值(光敏电阻模拟输出AO)。
  • 其中P3.3连接DO,P3.4连接AO
  1. 引脚配置
    在这里插入图片描述
    2.实现代码
	//DO
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET){
		LCD_DisplayStringLine(Line7, (u8*)"       DO:High     ");
	}else{
		LCD_DisplayStringLine(Line7, (u8*)"       DO:Low      ");
	}
	//AO	
	tmp = getADC();
	snprintf((char *)str, sizeof(str), " R-P:%.2fK  ", tmp/(4096.-tmp)*10);
	LCD_DisplayStringLine(Line6, str);
	HAL_Delay(200);
	
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值