同步操作将从 立创开发板/裸机版基于立创梁山派的21年电赛F题智能送药小车 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
详情查看工程的BSP目录下对应的文件
文件首先定义了三个常量数组,方便程序的初始化和修改,后面想要再加入其他需要控制的灯,只需要在这下面三个数组中再定义就可以了。
LED_PORT[]
: 常量数组,包含了不同LED灯对应的GPIO端口。例如,LED1_GPIO_PORT
,LED2_GPIO_PORT
,等。LED_PIN[]
: 常量数组,包含了不同LED灯对应的GPIO引脚。例如,LED1_PIN
,LED2_PIN
,等。LED_CLK[]
: 常量数组,包含了不同LED灯对应的GPIO时钟。例如,LED1_GPIO_CLK
,LED2_GPIO_CLK
,等。各个函数的作用:
bsp_led_gpio_init(led_type_def led)
: 这个函数初始化一个指定的LED灯。首先开启对应的GPIO时钟,然后设置GPIO模式为输出,并且将引脚的电平设置为低电平。这样就对LED的GPIO口进行了初始化。bsp_led_init(void)
: 这个函数初始化所有的LED灯,并将们全部设置为关闭状态。通过一个循环调用bsp_led_gpio_init
来初始化每一个LED灯,然后调用bsp_led_off
将LED关闭。有这个循环和.h文件中的枚举类型配合,我们可以不需要在增加LED灯时修改init函数了。bsp_led_on(led_type_def led)
: 这个函数将指定的LED灯打开。通过调用gpio_bit_set
函数将GPIO引脚电平设置为高电平,这样LED灯就会打开。bsp_led_off(led_type_def led)
: 这个函数将指定的LED灯关闭。通过调用gpio_bit_reset
函数将GPIO引脚电平设置为低电平,这样LED灯就会关闭。bsp_led_toggle(led_type_def led)
: 这个函数会切换指定LED灯的状态。如果LED灯是打开的,那么就会关闭;如果LED灯是关闭的,那么它就会打开。bsp_led_get_status(led_type_def led)
: 这个函数返回指定LED灯的状态。如果LED灯是打开的,那么就会返回1;如果LED灯是关闭的,那么就会返回0。使用这些函数,我们就可以方便的操作立创梁山派上的LED灯了。可以通过调用bsp_led_init()
函数来初始化所有的LED灯,然后通过调用bsp_led_on(LED1)
函数来打开第一个LED灯。当前是只控制了立创梁山派上的四个LED灯,电赛送药小车需要的三个红黄绿灯还没加上去。
这个文件里面文件有枚举和宏定义,主要是为了方便再添加LED灯时,改动较少:
首先是类型定义:
led_type_def
:这是一个枚举类型,代表了四个LED灯,LED1
、LED2
、LED3
、LED4
,以及一个代表LED数量的LED_MAX_NUM
。接下来看一下宏定义:
LEDx_PIN
: 这些宏定义了每个LED的GPIO引脚号。例如,LED1_PIN
定义了LED1的引脚号是GPIO_PIN_3
。LEDx_GPIO_PORT
: 这些宏定义了每个LED连接的GPIO端口。例如,LED1_GPIO_PORT
定义了LED1连接的是GPIOE
端口。LEDx_GPIO_CLK
: 这些宏定义了每个LED对应的GPIO时钟。例如,LED1_GPIO_CLK
定义了LED1对应的是RCU_GPIOE
时钟。最后就是一些函数原型了,具体介绍看上面.c文件的介绍。
详情查看工程的BSP目录下对应的文件
首先,还是定义了一系列的常量数组,比如COM_UART
、COM_UART_IRQn
、COM_UART_CLK
等,这些数组分别定义了各个UART通道的基础信息,比如串口基地址、中断号、串口时钟、GPIO时钟、复用功能,引脚等。
主要有两个函数:
bsp_uart_periph_init(uart_type_def _com_uart)
:这个函数用于初始化指定的UART。首先,开启GPIO和USART的时钟。然后,将GPIO引脚复用到USART的Tx和Rx。配置GPIO引脚为推挽输出和上拉,并设置了USART的各项参数,比如波特率、接收使能、发送使能等。最后,根据不同的UART设备,配置不同的中断优先级。bsp_uart_init(void)
:此函数初始化所有的UART设备,遍历所有的UART设备,并调用bsp_uart_periph_init(uart_type_def _com_uart)
函数进行初始化。最后,对于printf
函数的重定向:
#if !defined(__MICROLIB)
:这一行检查是否定义了__MICROLIB
宏。如果没有定义(即不使用微库),就编译下面的代码。#if (__ARMCLIB_VERSION <= 6000000)
:这一行检查ARM编译器的版本。如果版本小于或等于6.0.0,就编译下面的代码。__FILE
结构体:
__FILE
结构体。在这里只包含一个句柄,没啥实际作用,主要是防止编译器报错。__stdout
变量:
FILE __stdout;
定义了一个全局变量,代表标准输出。这个变量将被用于重定向printf
等函数的输出。_sys_exit
函数:
fputc
函数:
usart_data_transmit(COM_UART[0], (uint8_t)ch);
调用一个函数将字符发送到USART的数据寄存器。while(RESET == usart_flag_get(COM_UART[0], USART_FLAG_TBE));
等待直到USART的发送缓冲区为空。return ch;
返回写入的字符。现在的单片机flash都挺大的,如果flash够用的话,还是推荐大家直接用标准库,不要太为难自己。
就是对不同的串口进行宏定义,波特率等参数可以直接在这里修改生效。
这里其实就只是初始化,除了printf也没有什么能主动调用的函数了。可以给大家演示一下:
之前也提到过,如果不用微库也不处理芯片的半主机模式的话,芯片在不连单片机时会出现卡死的情况,现在来模拟一下这个情况。
实际串口数据的处理还是要在其他文件实现,比如中断接收,串口DMA接收等。
详情查看工程的BSP目录下对应的文件
蜂鸣器是一种常见的声音输出设备,可以发出各种声音或音调。它们广泛应用于家用电器、电子设备、汽车、安全系统等领域。以下是蜂鸣器的主要种类及其使用场景。
蜂鸣器主要分为两大类:有源蜂鸣器和无源蜂鸣器。
有源蜂鸣器内部集成了一个振荡电路,当直接接入电源时就可以发出声音。由于内部已经集成了振荡电路,有源蜂鸣器的控制相对简单,只需要提供一个恒定的电源电压即可。但是,这种蜂鸣器的音调和音量调节较为有限。
与有源蜂鸣器不同,无源蜂鸣器没有内置振荡电路。要使无源蜂鸣器发声,需要提供一个外部的交流信号(如方波或PWM信号)。这种蜂鸣器的优点是可以通过调整外部信号的频率和占空比来实现更丰富的音调和音量控制。
我这里选用的无源蜂鸣器,他的驱动频率是4000Hz。
蜂鸣器的PWM用的是定时器12,他的时钟频率是240MHz,在下面的代码中,无源蜂鸣器需要的发声最佳频率是4000Hz,最佳频率是器件手册给的,通常情况下是蜂鸣器发声声音最大时频率。
想输出确定PWM频率的信号,首先要知道当前所用定时器的时钟频率,查看GD32F4xx用户手册中的图4-2.时钟树:
送药小车项目中,用的是外部时钟,APB1和APB2配置如下所示:
//截取至system_gd32f4xx.c
system_clock_240m_25m_hxtal();
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB/2 */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;
/* APB1 = AHB/4 */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;
可知AHB为240Mhz,定时器的时钟有两个路线,一路定时器的时钟从APB1过来,又因为上面这个TIMERSEL时钟源选择这个位,APB1是四分频,定时器的时钟要是APB时钟的两倍。所以APB1下时钟频率为120MHz,也就是TIMER1,2,3,4,5,6,11,12,13是120MHz。另一路定时器时钟从APB2过来,这些定时器也要乘以2,所以TIMER0,7,8,9,10时钟频率为240MHz。
//定时器12时钟频率配置关键代码
timer_param_type.period = 1000-1; //4000Hz
timer_param_type.prescaler = 30-1; //120Mhz/30=4000000Hz
beep_pwm_gpio_init()
: 这个函数负责初始化控制蜂鸣器的GPIO引脚和复用为PWM输出模式。beep_timer_init()
: 这个函数负责初始化PWM的定时器。首先启动蜂鸣器定时器的时钟,然后初始化定时器的参数,包括计数方式(向上计数)、预分频器值(用来降低定时器的频率)、计数器的最大值(用来设置PWM的频率),然后初始化定时器通道的参数,设置PWM的极性(高电平有效)、使能输出、禁止反向输出,最后配置定时器通道为PWM模式并使能定时器。buzzer_beep_set(uint16_t _tone_freq, uint8_t _volume)
: 这个函数用来设置蜂鸣器的音调和音量。参数_tone_freq
用来设置PWM的频率,也就是音调;参数_volume
用来设置PWM的占空比,也就是音量。这个函数内部会重新计算PWM的周期和脉冲值,并重新配置定时器的参数。beep_init()
: 这个函数负责初始化蜂鸣器,它会调用上面的两个初始化函数,初始化GPIO引脚和PWM定时器。简单用法是这样的:首先调用beep_init()
函数来初始化蜂鸣器,然后调用buzzer_beep_set()
函数来设置蜂鸣器的音调和音量。但是这个蜂鸣器驱动还不能做到让蜂鸣器随意发出设置的音调和时间(这里指的是单纯通过延时,调整占空比和频率这个实现起来麻烦也不容易理解),需要再实现一个上层的驱动(有了这个驱动就可以实现一个简单的蜂鸣器播放器了),会在下一篇文档中介绍。
简单使用如下:
int main(void)
{
board_init();
beep_init();
uint16_t _freq = 4000;
uint8_t _volume = 50;
uint32_t _on_time = 200000;
uint32_t _off_time = 1000000;
while (1)
{
buzzer_beep_set(_freq,_volume);
delay_us(_on_time);
buzzer_beep_set(0,0);
delay_us(_off_time);
}
}
大家可以实际试试,改变PWM频率和占空比,蜂鸣器的叫声会怎样变化。
用无源蜂鸣器就可以做一些有趣的实验了:
比如让他播放一首小星星:
// 定义音符频率
#define NOTE_C4 261
#define NOTE_D4 293
#define NOTE_E4 329
#define NOTE_F4 349
#define NOTE_G4 392
#define NOTE_A4 440
#define NOTE_B4 493
// 定义"小星星"的音符和节奏,这些值代表了歌曲的旋律
int melody[] = {
NOTE_C4, NOTE_C4, NOTE_G4, NOTE_G4, NOTE_A4, NOTE_A4, NOTE_G4,
NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_C4,
NOTE_G4, NOTE_G4, NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_D4,
NOTE_G4, NOTE_G4, NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_D4,
NOTE_C4, NOTE_C4, NOTE_G4, NOTE_G4, NOTE_A4, NOTE_A4, NOTE_G4,
NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_C4
};
//定义每个音符的节奏,这些值代表了每个音符的时长
int noteDurations[] = {
4, 4, 4, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 2
};
int main(void)
{
board_init();//初始化开发板,配置所需的时钟和硬件资源
beep_init(); // 初始化蜂鸣器,其实就是配置PWM
// 计算歌曲的长度,即音符的数量
int songLength = sizeof(melody) / sizeof(melody[0]);
while (1)// 主循环,不断重复播放歌曲
{
// 遍历歌曲中的每个音符
for (int thisNote = 0; thisNote < songLength; thisNote++)
{
// 计算当前音符的时长,单位为毫秒
int noteDuration = 1000 / noteDurations[thisNote];
// 设置蜂鸣器的频率和音量,播放当前音符
buzzer_beep_set(melody[thisNote], 100);
// 为了区分音符,每个音符之间有短暂的停顿
// 使用微秒延时函数,因此乘以1000将毫秒转换为微秒
delay_us(noteDuration * 1000);
}
}
}
好像有点难听,不确定的话再听一听。
上面用了delay_us
,执行到这个函数的时候cpu就阻塞了。在这个基础上再添加别的逻辑代码就很难维护了,所以后面会再实现一个非阻塞的蜂鸣器驱动,我们只需要定义好要让蜂鸣器工作的频率,占空比,响的时间,停的时间,然后开一个软件定时器定时调用它就行了。会在下一节进行介绍。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。