使用Pico W做底盘,需要至少有以下外设:GPIO,PWM,定时器,编码器读取和WiFi。GPIO,PWM,UART,定时器,这几个外设都有例程可以参考,移植起来也比较容易,这里一起介绍,顺便介绍一下工程移植过程。
目标
创建呼吸灯工程,设置两个个引脚为PWM输出连接LED,在定时器中断中改变PWM输出占空比,并通过UART输出定时器的间隔。
PWM简介
在写代码之前需要大致了解该芯片的PWM外设,PicoW主控芯片是RP2040,所以如果要详细的了解相关外设,可阅读芯片手册,在帖子最后有下载。PWM在数据手册的523页,所有的30个GPIO都可以用来输出PWM,一共16个PWM通道,由8个2通道的slices组成,也就是一个slices可以输出给两个引脚,可设置不同的占空比等。
PWM有一个不断增加计数器,通过TOP寄存器的值来周期,通过设置比较的值来控制占空比。普通模式(free-running模式)如下图。
PWM的频率公式如下。
fsys:PWM时钟,使用的CLK SYS,默认是等于PLL SYS=125Mhz
TOP:周期设置寄存器,默认65535
CSR_PH_CORRECT:相位校正模式,默认为0(普通模式)
DIV_INT:是时钟分配寄存器,1~255,默认为1
DIV_FRAC:FRAC是fractional的缩写,也就是小数,0~15,默认0
新建工程
使用前面介绍的方法打开工具“pico project generato”,勾选“HW TImer”,发现并没有PWM相关的模块可以勾选,这里我们尝试选择小车工程会需要的外设如下。
将例程中的“.viscode”文件夹复制到生成的工程中。生成的文件与大致的功能如下。
打开工程
打开“Pico - Visual Studio Code”软件,在软件中打开刚刚生成的工程文件夹。
会自动弹出选择编译工具,这两个任选一个都行,如果打开的时候错过了,可以点击最下方状态栏的“No Kit Selected”重新选择。
配置工程
重点关注“CMakeLists.txt”文件,这是CMake的配置文件。在“CMakeLists.txt”文件找到target_link_libraries,该指令的作用为将目标文件与库文件进行链接。
可以看到已有两个库文件,就是我们在工具中勾选的,从例程中得知,PWM的库文件名叫做“hardware_pwm”,因此添加该库文件如下。
还有一个add_executable指令,该指令的含义是使用“Test_Timer_PWM.c ”源文件生成“Test_Timer_PWM”可执行文件。
可以有多个该指令,生成多个可执行文件,可配合“target_link_libraries”指令链接不同的库,生成不同的可执行文件。
这里增加一个“peripherals.c”文件用来写外设的配置代码,如下。
新建“peripherals.c”与“peripherals.h”文件在根目录。
编写代码
PWM初始化如下:
void PWM_init(){
gpio_set_function(PIN_PWM_1, GPIO_FUNC_PWM);//设置引脚为PWM功能
gpio_set_function(PIN_PWM_2, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(PIN_PWM_1);//根据GPIO获取对应的slice号
pwm_config config = pwm_get_default_config();//获取默认的设置
pwm_config_set_clkdiv(&config, 4.f);//配置该slice的PWM的频率,4分频clk_sys
pwm_init(slice_num, &config, true);//配置并启动该PWM
}
定时器初始化如下:
void Timer_init(){
//配置定时器,-50表示50ms定时,负数表示从进入该函数开始计算,repeating_timer_callback是回调函数名
add_repeating_timer_ms(-50, repeating_timer_callback, NULL, &timer);
}
定时器回调函数如下:
bool repeating_timer_callback(struct repeating_timer *t) {
static absolute_time_t t_from;
absolute_time_t t_to;
int64_t t_delta;
static int fade = 0;
static bool going_up = true;
t_to=get_absolute_time();//获取上电开始的绝对时间
t_delta=absolute_time_diff_us(t_from,t_to);//获取时间差,转化为us
t_from=t_to;//保存上次的值
printf("time_diff_us: %8d\n", (int)t_delta);
if (going_up) {
++fade;
if (fade > 255) {
fade = 255;
going_up = false;
}
} else {
--fade;
if (fade < -255) {
fade = -255;
going_up = true;
}
}
pwm_set_gpio_level(PIN_PWM_1, fade * fade);//最大值65535,数值的平方更适合呼吸灯
pwm_set_gpio_level(PIN_PWM_2, 65535-fade * fade);
}
运行后,使用串口助手连接仿真器生成的串口,可以看到返回的数值都是50000,说明定时器非常的精准。
使用LED灯连接Pin14和Pin15另一端连接GND就可以看到灯交替闪烁了。使用示波器观察引脚频率,结合前面的PWM频率计算公式,理论上应该是125M/65536/4=476.84Hz,示波器实测的频率为476.9Hz,如下。