【蓝桥杯嵌入式】

一 .LED灯

1 .cubeMX配置

把pb8~pb15配置成output, pd2也配置成output, 把pb8~pb15的输出引脚配置成高电平
pd2默认
在这里插入图片描述
在keil中创建一个bsp文件,方便提交

2 .keil中代码

.c文件

#include "bsp_led.h"

void Disp_Led(uint16_t led_num)
{
  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOC,led_num<<8,GPIO_PIN_RESET);
  HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

.h文件

#ifndef __BSP_LED_H
#define __BSP_LED_H

#include "main.h"

void Disp_Led(uint16_t led_num);


#endif

二 .LCD屏(移植)

找到官方给的lcd例程,将其复制到自己的工程文件夹中

在这里插入图片描述
在这里插入图片描述
以下两部分一般放在while之前。

lcd初始化:

 	LCD_Init();    //初始化
    LCD_Clear(Black);    //清屏
    LCD_SetBackColor(Black);   //背景色
    LCD_SetTextColor(White);   //前景色

显示:

  char text[30];   
  sprintf (text,"        ni hao ya      " );
  LCD_DisplayStringLine(Line0,(uint8_t *)text);  
  LCD_DisplayStringLine(Line1, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line2, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line3, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line4, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line5, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line6, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line7, (unsigned char *)"                    ");       
  LCD_DisplayStringLine(Line8, (unsigned char *)"                    ");
  LCD_DisplayStringLine(Line9, (unsigned char *)"                    ");

三 .按键

1 .一般按键

配置成上拉模式
在这里插入图片描述

开启tim1(根据实际情况而定)的定时器和中断,配置成10ms方便消抖

在这里插入图片描述
key.c文件

#include "key.h"
#include "stdio.h"
struct keys key[4]={0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance==TIM1)
  {
    key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
    key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
    key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
    key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
    
    for(char i=0;i<4;i++)
    {
      switch (key[i].jude_sta)
      {
        case 0:
        {
          if(key[i].key_sta==0)
          {
            key[i].jude_sta=1;
          }
        }
        break;
        case 1:
        {
          if(key[i].key_sta==0)
          {
            key[i].jude_sta=2;
            key[i].key_flog=1;
          }
          else
          {
            key[i].jude_sta=0;
          }
        }
        break;
        case 2:
        {
          if(key[i].key_sta==1)
          {
            key[i].jude_sta=0;
          }
        }
        break;
      }
    }
  }
}

key.h文件

#ifndef __KEY_H
#define __KEY_H

#include "main.h"
#include "stdbool.h"

struct keys
{
  bool key_sta;
  char jude_sta;
  bool key_flog;
};


#endif /*__KEY_H*/

2.长按键(按压时间>70ms)

.c文件

#include "key_chang.h"

struct key_chang keys_chang[4]={0};


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance==TIM1)
  {
    keys_chang[0].key_chang_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
    keys_chang[1].key_chang_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
    keys_chang[2].key_chang_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
    keys_chang[3].key_chang_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
    
    for(char i=0;i<4;i++)
    {
      switch (keys_chang[i].jude_sta)
      {
        case 0:
        {
          if(keys_chang[i].key_chang_sta==0)
          {
            keys_chang[i].jude_sta=1;
            keys_chang[i].key_chang_time=0;
          }
        }
        break;
        case 1:
        {
          if(keys_chang[i].key_chang_sta==0)
          {
           keys_chang[i].jude_sta=2;   
          }
          else
          {
            keys_chang[i].jude_sta=0;
          }
        }
        break;
        case 2:
        {
          if(keys_chang[i].key_chang_sta==1)
          {
            keys_chang[i].jude_sta=0;
            if(keys_chang[i].key_chang_time<70)
            {
              keys_chang[i].key_flog=1;
            }
          }
          else
          {
            keys_chang[i].key_chang_time++;
            if(keys_chang[i].key_chang_time>70)
            {
              keys_chang[i].key_chang_flog=1;
            }
          }
        }
        break;
      }
    }
  }
}

.h文件

#ifndef __KEY_CHANG_H 
#define __KEY_CHANG_H

#include "main.h"
#include "stdbool.h"

struct key_chang 
{
  char jude_sta;
  bool key_chang_sta;
  bool key_chang_flog;
  uint16_t key_chang_time;
  bool key_flog;
};

#endif /*__KEY_CHANG_H*/

3 .双击按键(针对短按键)

.c文件

#include "key_shuang.h"

struct key_chang keys_chang[4]={0};


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance==TIM1)
  {
    keys_chang[0].key_chang_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
    keys_chang[1].key_chang_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
    keys_chang[2].key_chang_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
    keys_chang[3].key_chang_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
    
    for(char i=0;i<4;i++)
    {
      switch (keys_chang[i].jude_sta)
      {
        case 0:
        {
          if(keys_chang[i].key_chang_sta==0)
          {
            keys_chang[i].jude_sta=1;
            keys_chang[i].key_chang_time=0;
          }
        }
        break;
        case 1:
        {
          if(keys_chang[i].key_chang_sta==0)
          {
           keys_chang[i].jude_sta=2;   
          }
          else
          {
            keys_chang[i].jude_sta=0;
          }
        }
        break;
        case 2:
        {
          if((keys_chang[i].key_chang_sta==1)&&(keys_chang[i].key_chang_time<70))
          {
            if(keys_chang[i].key_shuangclick_num==0)
            {
              keys_chang[i].key_shuangclick_num=1;
              keys_chang[i].key_shuangclick_time=0;            
            }
            else
            {
              keys_chang[i].key_shuangclick_flog=1;
              keys_chang[i].key_shuangclick_num=0;
            }
            keys_chang[i].jude_sta=0;
          }
         else if((keys_chang[i].key_chang_sta==1)&&(keys_chang[i].key_chang_time>=70))
          {
            keys_chang[i].jude_sta=0;
          }
          else
          {
            if((keys_chang[i].key_chang_time>=70))
            {
              keys_chang[i].key_chang_flog=1;
            }
            keys_chang[i].key_chang_time++;
          }
        }
        break;       
      }
      if(keys_chang[i].key_shuangclick_num==1)
      {
        keys_chang[i].key_shuangclick_time++;
        if(keys_chang[i].key_shuangclick_time>35)
        {
          keys_chang[i].key_flog=1;
          keys_chang[i].key_shuangclick_num=0;
        }
      }
    }
  }
}

.h文件

#ifndef __KEY_SHUANG_H 
#define __KEY_SHUANG_H

#include "main.h"
#include "stdbool.h"

struct key_chang 
{
  char jude_sta;
  bool key_chang_sta;
  bool key_chang_flog;
  uint16_t key_chang_time;
  bool key_flog;
  uint16_t key_shuangclick_num;
  uint16_t key_shuangclick_time;
  bool key_shuangclick_flog;
};

#endif 

注意:结构体在main.c中调用时要extern声明,且还要打开定时器中断:
HAL_TIM_Base_Start_IT(&htim1)

四.pwm波的输出

1.cubeMX配置

在这里插入图片描述
其中用到的定时器,要根据实际情况选择,
周期T=(psc+1)*ARR/内部时钟,其中的占空比由ARR来决定的,一般ARR设置为100,方便占空比的计算。

要开HAL_TIM_PWM_START(&htimx,TIM_CHANNEL_X)
若要改变占空比,__HAL_TIM_SetCompara(&htimx,TIM_CHANNEL_X,占空比值),对其占空比进行设置

具体情况要根据题目来.

五 .输入捕获

在这里插入图片描述

1 .原理

是对要捕获的波进行频率,占空比的测量,实质时,对要捕获的波进行掐时 ,在上升沿处掐时,可以算频率,在下降沿掐时可以算占空比,一个注意的地方:在配置输入捕获时要配置PSC与ARR(相当于定时器)其一个周期一定要大于要捕获的波的周期(一般大两倍),放置捕获不完全,换句话说,如果小了,当波的下一个上升沿还未到来时,我的计数时间已经从新从0开始了,必然造成错误

2 .cubeMX配置

在这里插入图片描述
在这里插入图片描述

3 .代码

将其放在按键的.c文件中

/********************输入捕获************************/
double frequency;
uint16_t duty_cycle;

double frequency_jishuan;
uint16_t duty_cycle_jishuan;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)  //输入捕获回调函数
{
  if(htim->Instance==TIM3)
  {
    if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)//通道检测
    {
      frequency=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1); //获取通道一的直接测量值,用于计算频率
      duty_cycle=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);//获取通道二的直间接量值,用于计算占空比

      __HAL_TIM_SetCounter(htim,0);//清零计数值
      
      frequency_jishuan=(80000000/80)/frequency;//计算频率
      duty_cycle_jishuan=(duty_cycle/frequency)*100;//计算占空比,因为占空比就等于上升沿的计数值比上整个周期的值再乘以100
      
      HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);//开启通道一
      HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);//开启通道二
    }
  }
}

主函数初始化两个通道:

HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);//计算频率的通道
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);//计算高电平时间的通道

六 .ADC

1 .cubeMX的配置

配置比较简单
在这里插入图片描述

2 .代码

.c文件

#include "bsp_adc.h "

 
float getADC(ADC_HandleTypeDef *pin)
{
    uint16_t adc;
    HAL_ADC_Start(pin);  //开启adc通道
    adc = HAL_ADC_GetValue(pin); // 获取adc读出返回的值
    return adc*3.3/4096;  //转换成0~3.3V的电压,因为我们的ADC2是12bit,也就是2的12次方,所以要除以4096
}

.h文件

#ifndef __BSP_ADC_H 
#define __BSP_ADC_H

#include "main.h"

float getADC(ADC_HandleTypeDef *pin);


#endif 

七 .IIC读写EEPROM

1 . cubeMX配置

在这里插入图片描述
把PB6、PB7的GPIO配置成输出模式即可

在这里插入图片描述

然后导入官方资料包给的IIC文件

在这里插入图片描述

2 .代码

在导入的.c文件后面加入下面代码,记得.h文件中声明

void eeprom_write(unsigned char adder,unsigned char dat)
{
 
    I2CStart();
    I2CSendByte(0xa0);
    I2CWaitAck();
    I2CSendByte(adder);
    I2CWaitAck();
    I2CSendByte(dat);
    I2CWaitAck();
    I2CStop();
 
}

 
unsigned char eeprom_read(unsigned char adder)
{
    unsigned char datt;
    I2CStart();
    I2CSendByte(0xa0);
    I2CWaitAck();
    I2CSendByte(adder);
    I2CWaitAck();
    I2CStop();
        
    I2CStart();
    I2CSendByte(0xa1);
    I2CWaitAck();
    datt = I2CReceiveByte();
    I2CWaitAck();
    I2CStop();
    return datt;
}
 

我们的EEPROM一个数据存放单元只能存放一个字节的数据

如果需要存入一个int(两个字节)类型的数据,需要分开存放进行写入,注意写入需要一定的时间,因此需要进行一个10ms的延时

读的时候需要进行位操作,把第一个字节的数据移到高八位,再与上我们的低八位即可

写:

read_count1 = eeprom_count >> 8;
read_count2 = eeprom_count&0xff;
eeprom_write(1,read_count1);
HAL_Delay(10);
eeprom_write(2,read_count2);

读:

eeprom_count = (eeprom_read(1)<<8) + eeprom_read(2);

八 .串口通信

1.cube

配置波特率以及开启中断.
在这里插入图片描述
在这里插入图片描述

2.代码

串口的接收:

char data[30];
uint8_t rx;
uchar rx_flag;
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
 
    data[rx_flag++] = rx;
    HAL_UART_Receive_IT(&huart1,&rx,1);
}

//还可以这样写
uint8_t Rxbuff[30];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		// 重新使能中断
		HAL_UART_Receive_IT(huart,(uint8_t *)&Rxbuff,sizeof(Rxbuff)); 
	}
}


主函数声明一下:HAL_UART_Receive_IT(&huart1,&rx,1);
接收例子:

 
void uart_porc(void)
{
    sscanf(data,"%s",uart_rx);  //把接受的字符串写到uart_rx字符串数组里面
    if(rx_flag>0)   //如果接收到字符
    {
        if(rx_flag == 3)   //判断接受的字符串长度为3
        {
            char temp[20];
            sprintf(temp,"%s",uart_rx);
            LCD_DisplayStringLine(Line3,(unsigned char *)temp);    
        }
        else
        {
            char temp[30];
            sprintf(temp,"error\r\n");
            HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
        }    
    }
    
    rx_flag = 0;memset(data,0,30);  //执行完接受记得把接收字符串数组和数组标记清零
}

串口的发送:

char temp[30];
sprintf(temp,"hello world\r\n");
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);

串口的发送就很简单,只需调用下面的函数即可;

*HAL_UART_Transmit(&huart1,(uint8_t )temp,strlen(temp),50);

其中,只是一个大概的总结,推荐一个博主,基本全面
链接: https://blog.csdn.net/qq_63856395/category_12244665.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值