蓝桥杯嵌入式备赛

考点
请添加图片描述

一、LED灯&锁存器
由于蓝桥杯的板子LCD与LED有几个引脚是共用的,因此不能向51那样直接位操作或者直接配置寄存器来实现流水灯之类的操作,而是需要用到锁存器,
由于我是速通,锁存器具体原理与功能就不深究,能达到功能就可以.
请添加图片描述
首先在cubeMX中将PC8 - PC15,设置为推挽输出模式,默认高电平(主要与之前学的51单片机能不弄混),分析上述电路图得知,当输出为低电平的时候可以点亮,但是还需要完成锁存器的操作,将数据写入,完了之后这八个引脚就可以给LCD使用了(我随便理解的,不必深究).
锁存器涉及到PD2引脚,设置为推挽输出,默认为低电平,上面led的设置为输出好理解,那么PD2设置为输出其实就是为了给锁存器提供是否写入的信号,所以肯定是输出.

HAL_GPIO_WritePin(GPIOx, GPIO_PIN_x, 0/1); //设置某个(些)引脚输出的电平状态
/*例如*/
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, 0);//将PD2设为低电平
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 |GPIO_PIN_9 , 1);//将PC8和PC9设为高电平
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, 0); //将PC0 - PC15设为低电平
配合锁存器代码示例
void dis_led(unsigned char dis_led)
{
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,dis_led<<8,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

结合第十届省赛题,如果要实现LDx亮灭:

	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7<<x,GPIO_PIN_RESET); 
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);

只需要让GPIO_PIN_7左移x位就可以实现x号LED灯的单独亮灭,便于通过一个变量来控制.
二、读取按键值
10ms产生一次中断,执行中断回调函数读取四个按键引脚的电平状态
主要考点为单击,双击,长按键

首先配置cubeMX
①选择定时器3,每10ms产生一次中断
②将PB0 PB1 PB2 PA0配置为上拉输入(无输入时由于上拉电阻,默认为高电平)
设置完成后进入keil
首先打开中断:

HAL_TIM_Base_Start_IT(&htim3);//开启定时器3中断

编写中断回调函数: 将单击,双击,长按键封装在一个函数中

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM3)
    {
        key[0].key_status = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
        key[1].key_status = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
        key[2].key_status = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
        key[3].key_status = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
 
        for (int i=0; i<4; i++)
        {
            switch (key[i].click_status)
            {
                case 0:
                    if (key[i].key_status == GPIO_PIN_RESET)    key[i].click_status = 1;
                    break;
                case 1:
                    if (key[i].key_status == GPIO_PIN_RESET)
                    {
                        key[i].click_status = 2;
                        key[i].click_time = 0;
                    }
                    else    key[i].click_status = 0;
                    break;
                case 2:
                    if (key[i].key_status == GPIO_PIN_RESET)    key[i].click_time++;
 
                    else if (key[i].key_status==GPIO_PIN_SET && key[i].click_time>=70)
                    {
                        key[i].long_flag = 1;
                        key[i].click_status = 0;
                    }
 
                    else if (key[i].key_status==GPIO_PIN_SET && key[i].click_time<70)
                    {
                        switch (key[i].double_status)
                        {
                            case 0:
                                key[i].double_status = 1;
                                key[i].double_time = 0;
                                break;
                            case 1:
                                key[i].double_flag = 1;
                                key[i].double_status = 0;
                                break;
                        }
                        key[i].click_status = 0;
                    }
                break;
            }
 
            if (key[i].double_status == 1)
            {
                key[i].double_time++;
                if (key[i].double_time >= 35)
                {
                    key[i].single_flag = 1;
                    key[i].double_status = 0;
                    key[i].double_time = 0;
                }
            }
        }
    }
}

编写完成后使用在LCD屏上显示,检测一下代码
cubeMX配置LCD 将LCD有关的引脚全部设置为推挽输出
ps: 但是有几次我忘记了,写完代码好像也能直接用

测试通过

三、LCD显示
使用官方提供的例程,创建工程后将lcd.h,lcd.c还有fonts.h复制到BSP文件夹下,还需要移植请添加图片描述
接着打开官方提供的LCD中main.c例程
请添加图片描述
就可以实现LCD显示功能
有几次忘记将LCD的几个io口设置为output了,但是发现没有影响.

四、PWM输出

1.PWM输出,选定一个引脚,配置定时器,将通道设置为pwm generation模式
在keil中首先一定要打开pwm的定时器,接着编写回调函数就可以不断产生pwm方波了.
请添加图片描述
如果要修改频率与占空比需要用到几个函数:
①占空比可改:

if(key[1].key_flag == 1)
    {
        key[1].key_flag = 0;
        PA6_duty += 10;
        if(PA6_duty >= 100)
        {
            PA6_duty = 10;
            __HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1,PA6_duty);
        }
    }

②频率可改:
优选通过修改预分频系数来修改频率

PWM频率 = 定时器时钟频率 / (预分频器值 + 1) / (自动重装载值 + 1)
占空比 = (比较值 / (自动重装载值 + 1)) * 100%

__HAL_TIM_PRESCALER(&htim2,  pscVal); //设置预分频系数

四、ADC模拟输入
ADC能够采集模拟信号转化为数字信号,在蓝桥杯比赛中主要考察R37的模拟输入,读取其电压值
第一种情况:直接采集

float getADC(ADC_HandleTypeDef *pin)
{
    unsigned int adc;
    HAL_ADC_Start(pin);
    adc = HAL_ADC_GetValue(pin);
    return adc*3.3/4096;
}

第二种情况: 对采集到的信号进行滤波

暂时略 以后有精力再说…

五、UART通信
首先cubeMX配置
根据原理图,将PA9还要PA10分别设置为RX TX.请添加图片描述
接着将USART1设置为异步通信模式(异步通信就是一个发送,另一个接收,不能同时收发数据)

在这里插入图片描述
波特率设置为9600,
同时一定不能忘记一定要在NVIC中打开中断!!!
请添加图片描述
第一种情况:发数据
只需要通过这一个函数即可
但是在测试过程中出现了一个未知的错误,就是发送ADC采样的值始终比在LCD屏上显示的小0.2左右

void tx_fun(void)
{
    char text_tx[30];
    sprintf(text_tx," wjg da shuai bi");
    HAL_UART_Transmit(&huart1,(uint8_t *)text_tx,strlen(text_tx),50);
}

第二种情况:接收数据
首先需要打开USART1的接收中断(因为接收到字符时刻是未知的,因此需要通过中断来检测)

HAL_UART_Receive_IT(&huart1,&rx,1); 

注意这里也是带IT的 目前为止打开中断或者定时器需要带有IT结尾的 有:

HAL_TIM_BASE_START_IT()
HAL_UART_Receive_IT(&huart1,&rx,1);

USART1的引脚接收到数据时会触发中断,调用中断回调函数
以下是HAL库中封装的回调函数,与按键扫描一样,去usart.h文件中找与USART相关的,同样也是在最后有声明.请添加图片描述
**注意:**这里带half的是精度更高的(ai说的),意思可能是半个中断周期执行一次,但是我暂时没有用到就不深究了.

好的,接下来编写中断回调函数

char rx_data[30];
uint8_t rx;
unsigned char data_index;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    rx_data[data_index++] = rx;
    HAL_UART_Receive_IT(&huart1,&rx,1);
}

每次通过HAL_UART_Receive_IT(&huart1,&rx,1)函数接收一个字符赋值给字符数组
接着还需要在main.c中,根据接收到的字符格式,编写判断是否接收成功的函数

void rx_fun(void)// 接收定长数据
{
    if(data_index>0)
    {
        if(data_index == 22)
        {
        	//分割接收到的字符格式
            sscanf(rx_data,"%4s:%4s:%12s",car_type,car_data,car_time); 
        }
        else
        {
            char temp[20];
            sprintf(temp,"  Error \r\n");
            HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
        }
        data_index = 0;
    }   
}
//接收不定长数据:通过判断最后一位是不是换行符
char temp[20];
void rx_fun(void)
{
	if(data_index != 0)
	{
		if(rxdata[rx_index] == '\0')
		{
			sprintf(temp,"ok\r\n");
	    HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
		}
		rx_index = 0;											//指针归位
		memset(rxdata,0,sizeof(rxdata));		//初始化为0
		
	}
}

在while(1)中,编写如下

     if(data_index !=0)  
      {
          int temp = data_index;
          HAL_Delay(1);
          if(temp == data_index)
          {
            rx_fun();memset(rx_data,0,30);
          }
      }

ps:这里不太懂…但是能实现功能.

五、PWM捕获

1.功能要求
使用PWM捕获测量555定时器产生的PWM波的频率和占空比(如图所示).
请添加图片描述
在蓝桥杯嵌入式板子中 PA15和PB4是直接与这两个定时器相连的,因此我们需要配置这两个引脚来捕获

2.频率测量
首先配置cubeMX
将PA15和PB4分别配置为定时器通道1的input capture direct mode,同时打开NVIC中的中断使能.

未完待续…

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w沉默味道w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值