蓝桥杯嵌入式组复习过程

今年的蓝桥杯嵌入式组是以stm32G431RBT6作为主控,与前年不同与去年相同。

比赛使用的下载器是DAP调试器,使用CubeMX快速创建工程,Keil5作为编译器,第一次使用CunbeMX创建stm32G431RBTx的Keil工程后,Keil会自动下载关于此型号设备的资源,需要等待一段时间。工程创建好后,点击魔术棒,找到Debug将下载器改为CMSIS-DAP,然后点击settings,进入默认界面找到端口port,将类型改为sw,这与CunbeMX配置所选一致,使用Serial Wire方式下载。然后再Download中勾选Reset and Run。由于是第一次创建工程,这里要做一个添加,如图将上面的配置做好后我们就可以开始学习了。

一.点灯

在初学单片机时,上来第一个实际操作一般都以点灯为主,且是蓝桥杯比赛的考点。

这是官方给的产品手册,相比于常规的学习板来说它都是以LED作为点亮的器件,当导线接地,电流导通LED被点亮,但是与其他学习板不同的是。这里面的线路不是单连接一个开关,而是使用了一个锁存器。学过数电或者类似专业课的同学可以知道,锁存器中当输出端状态改变使能端LE为高电平时,锁存器会正常输出前面输入的信号,也就是同步改变。但当LE为低电平时,状态会被锁住,输出不会因为输入的改变而改变。这里要与触发器做好区分。所以当LE为高电平时,我们才可以改变LED的状态,这就意味着,在后面我们要根据题目对LED进行状态改变时,一定要记得将LE端电平拉高。

二.LCD

LCD这里不谈如何写清屏等函数如何设计,由于比赛直接提供LCD有关的库文件,这里我们需要学如何把官方给的库函数移植到工程里,在工程文件夹中加入BSP文件夹,我们之后所有的c和h文件都可以放在这里。将官方提供的lcd.c和lcd.h以及fonts.h都放在BSP文件夹里。接着,在KEIL工程里添加一个新的文件夹,也叫BSP,然后添加已存在的文件,将c文件放进去,最后一步,找到魔术棒里的C/C++选项,将BSP头文件路径添加进去,这样就大功告成了。将官方给的几个库函数熟练运用,非常简单。别忘了LCD初始化。

                        

三.定时器

定时器对于开发来说非常重要且是比赛考点,它的功能不仅仅局限于设定时间,更可以在定时的基础上完成其他高级功能。比如输出PWM等。F103系列有8个定时器,定时器6、7为基本定时器,2-5为通用定时器,1、8为高级定时器,而G4系列是多了三个通用定时器13、14、15。学习中常用的是通用定时器。所以在这里我们使用一个TIM4来完成一个定时器中断+定时器按键消抖的例子。由于常规的软件延时函数会导致阻塞、占用资源、定时不准确,所以使用定时器,硬件定时是最好的。

在CubeMX配置一个定时器,我们使用TIM2,在TIM2中打开Clock Source:Internal Clock,然后根据定时器计时配置分频数和重装载数。这里有个公式

注意我们使用的这款STM32官方例程中使用的Tclk是80MHz,只要不大于170MHz就好,那么这里以80MHz为例,计算一下想要设置定时时间为10ms,则T=0.01s,Tclk=80000000Hz。将这两个数带到公式里,然后找到合适的PSC和ARR即可。

进入工程,程序设计思路:

可以直接将回调函数写在main.c文件里,最好是可以单独创建两个文件,h文件主要是创建结构体,声明函数,c文件里就包括回调函数里的具体逻辑实现。在c文件中新建一个四位结构体对象,分别代表四个按键,将结构体里面的参数全部默认为0。然后使用EDA中状态机的方法开始模拟按键的状态,最后输出不同的结果,要知道,使用状态机的过程中,各个过程之间的转化是需要时间的,而这个时间就是设置的定时器时间,当按键按下进入第一个状态,等10ms过后依然是这个状态,则进入第二个状态,最后按键松开进入第三个状态,输出结果为主函数所利用。

不要忘了主函数中定义“extern struct 结构体名 结构体对象名[];(作用是使用其他文件中的变量)”以及定时器的启动HAL_TIM_Base_Start_IT(&htim4);

四、按键控制显示

此部分概括一下如何根据不同按键以及长按短按,将不同的内容显示到LCD上。前面说过,结构体里有多个参数。为了完成上述的要求,这里至少要设置五个元素(包含消抖):按键状态检测a、状态机状态序号b、按下标志c、长按键时间d、长按键标志e。

循环开始。初始b=0,当a==0,此时b=1,d=0;进入下一个状态b=1,若a==0,则b=1,否则b=0即回到初始状态;进入最后一个状态即b=2,此时定时器不断以10ms的时间间隔执行htim->Instance==TIM4内的语句,当a持续为0,每检测一次就将d+1.当按键松开即a=1,检测d的数值,根据题目要求时长看是否满足长按键条件,若满足则e=1(长按键),否则在松开按键时c=1(短按键),并将b、d清零以便下一次检测。此时根据四个按键的e或c的值在屏幕上输出不同内容,且执行显示语句后,都要将e或c清零。

五、pwm输出

有时题目中会要求输出一个**HZ频率的脉冲信号,那么这里所说的脉冲信号就是PWM波。比如我们这里要输出一个100HZ的脉冲信号,则我们需要满足HCLK/(PSC+1)*(ARR+1)=100,PSC和ARR要在CubeMX里配置好,并且要配置PWM Gerneration里的Pulse。进入工程,首先要打开PWM通道HAL_TIM_PWM_Start(&htima,TIM_CHANNEL_b);//打开PWM定时器a通道b。然后题目中若是要求占空比的变化我们可以使用__HAL_TIM_SetCompare(&htima,TIM_CHANNEL_b,number);这里number的范围在0-100。然后根据题目的逻辑以及前面完成的按键功能进行编程。

六.  信号发生器(555计数器)产生的信号测量

可以看到在比赛的开发板中是有两个旋钮控制频率输出的。并且根据原理图可以看到,在555计数器的THRES引脚连接着一个电位器,这个电位器就是我们的旋钮,通过这一旋钮改变电流电压值,使进入阈值引脚的信号发生变化,进而影响OUT引脚的输出(频率)。在OUT引脚后面可以看到有一个J10,这个可以通过一个跳线帽直接将信号输入到PA15或PB4,便于直接测量555定时器的信号频率。那么了解了原理之后插上J10和J9的跳线帽我们开始配置CubeMX以及程序的编写。

                

打开CubeMX找到PA15和PB4这两个引脚,点开发现分别由TIM2_CH1和TIM3_CH1,这两个就是我们测量时所需要的通道。将二引脚点亮之后将其通道一配置为直接输入(input capture direct mode)并改为上升沿捕获(Rising Edge)。生成代码。                                                                  首先在主函数中打开这两个定时器的通道一:    HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);//频率测量捕获定时器开启
 HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);                                                                            然后在之前的按键中断里写如下代码: 

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//中断捕获回调函数
{
	if(htim->Instance==TIM2)
	{
		count=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//读取计时值
		__HAL_TIM_SetCounter(htim,0);//把计时值清零
		frq=(80000000/80)/count;(80000000为HCLK,80为PSC+1)
		HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);//重新打开一下定时器
     }
}

 在主函数中调用frq这个变量就好了。                                                                                                 如果说想要测量脉冲信号的占空比,我们可以在CubeMX做如下配置:

这里加了个间接通道Channel2,且在两个通道(直接通道、间接通道)分别配置为上升沿计数和下降沿计数。上面我们测量了直接通道的计数值,那么这里同样测量间接通道值,然后将直接和间接的计数值带入公式:(间接/直接)*100。注:中断消息来源要选择直接输入通道。htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1                                           

七 ADC模数转换

模拟信号一般在实验室使用示波器能看到,而使用单片机进而显示电压状态需要的是数字信号。当然连续的模拟信号需要转化为一个个的数字信号,这里就需要使用ADC不断采集。                          打开CubeMX,并根据原理图找到两个电压采集旋钮的IO口。

然后打开两个ADC的single-end。                                                                   进入程序,HAL库给我们提供了非常大的方便内置了许多函数(记得当时使用51单片机+adc0809,中间要根据时序图采集,并且设置采集频率很麻烦)   HAL_ADC_Start(&hadc1);//打开ADC1         adc = HAL_ADC_GetValue(&hadc1);//获取ADC的值                                                                     我们的ADC配置时是12位,我们最后返回的值应该是(adc*3.3/2的十二次方)

八.UART串口通信

串口通信简单来说就是两个设备之间的数据传输,数据传输通过TXD和RXD,一般使用CH340用来USB转串口,输入/输出数据缓冲器(SBUF)等,关于串口有很多知识点,蓝桥杯嵌入式组的话学会怎么用就可以,具体知识点可以看我的另一篇博文串口通信编程_串口编程-CSDN博客

找到之前做过的频率实验,我们这次的目标是把频率发送到上位机。打开之前配置好的CubeMX,我们要在里面加点东西,找到PA9和PA10引脚。根据官方的原理图可以看到,PA9和PA10分别对应TX和RX,打开USART1,将Mode选为异步,然后根据题目设置波特率,最后打开串口中断,然后生成代码。进入到工程里,由于需要不断的向上位机发送数据,我们的处理应该在while循环里,下面是一个发送频率的案例

		char temp[20];
		sprintf(temp,"frq=%d\r\n",frq);
	    HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);

这里用到了一个HAL库内置函数HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);第一个参数是串口的句柄,选择使用哪个串口,第二个参数是发送的内容,第三个参数是发送字符串的长度,第四个参数Timeout是超时时间,代表某次执行函数,最多占用串口的时间。至此数据发送就已经完成了,很简单。下面说说串口通信接收。

还记得上面我们开启了串口中断吗。与定时器中断类似,这里也需要使用一个串口中断回调函数,并且每使用一次中断回调函数就应该接收一次数据,因此,在中断回调函数内需要使用接收函数HAL_UART_Receive_IT(&huart1,&rxdat,1);//这里的1是因为中断接收只能接收一个字符。由于每次只能接收一个字符,所以需要一个变量来接收单个字符,还需要一个字符串数组来存储字符串,当然还需要一个下标。这样基本的逻辑就对了。参考代码如下:

//串口接收的回调函数
char text[50];
uint8_t tex;
unsigned char index;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	text[index++]=tex;
	HAL_UART_Receive_IT(&huart1,&tex,1);//这里的1是因为中断接收只能接收一个字符
}

剩下的就需要看题目要求了,在主函数进行对应的处理就好,这里由于是使用串口调试助手,就一定会使用到输入数据给单片机,这里还是要注意输入的格式,根据题目输入的格式在代码中提前准备好。使用sscanf进行输入,这个知识点初学c语言时应该都学过,就不过多赘述了。

-------------------------------------------------------------

4月29日查成绩,省二

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值