本项目使用BeagleBone® Black板卡,简称BBB板,实现点灯操作,是Funpack3-5的BeagleBone® Black板卡的任务一。
本项目的主要难点在于需要使用PRU实现呼吸灯的操作,以及接收外部按键输入,切换呼吸灯的闪烁频率。
完成项目的第一步是熟悉板卡。BeagleBone® Black板卡是一个老板卡,应该有10+年,所以资料还是很齐全的,而且网上教程很多,同时板子自带的系统也很完备。
拿到板卡后,意外发现插上usb接口后,会在本地生成一个IP地址,能够直接通过IP地址访问系统,同时还可以直接使用cloud9的IDE进行程序编辑和编译下载操作。
熟悉系统后,发现系统内已经自带PRU的demo工程,可以直接编译成功,这就节省了大家编译环境和完成hello world的时间。
基于此,为了完成任务1:点灯!使用PRU控制一个LED实现呼吸灯,并且使用一个按键按下后切换闪烁的速度。需要进行需求的拆解。
任务拆解如下:
1)调用PRU进行GPIO的输出控制;
2)调用PRU进行GPIO的输入捕捉;
3)对输出进行逻辑控制,实现呼吸灯效果;
4)实现对呼吸灯效果的频率控制;
5)结合GPIO的输入捕捉和输出控制,完成任务描述的所有内容。
对于需求1):使用cloud9的demo工程:blinkInternalLED.pru0.c,确认点亮LED灯效果;
对于需求2):使用clude9的demo工程:blinkR30.pru0.c,进行修改,主要修改点为:重新配置输入捕捉的端口为P9_14,实现LED灯亮灭的功能。
对于需求3):使用cloud9的demo工程:blinkInternalLED.pru0.c,进行修改,主要修改点为:使用for循环控制点亮LED灯的delay周期和熄灭LED灯的delay周期。主要修改代码如下:
gpio1[GPIO_CLEARDATAOUT] = USR3; // Turn USR2 LED off
for(i = 0; i < u8index; i++)
{
__delay_cycles(500000000/500000); // Wait 1/200000 second
}
gpio1[GPIO_SETDATAOUT] = USR3; // On
for(i = 200; i > u8index; i--)
{
__delay_cycles(500000000/500000); // Wait 1/200000 second
}
对于需求4):基于需求3)工程,进行修改,主要修改点为:增加外部for循环,实现对呼吸灯步进频率的控制;
//呼吸灯频率控制部分
for(j = 0; j < 100; j++)// 100 cycle
{
gpio1[GPIO_CLEARDATAOUT] = USR3; // Turn USR2 LED off
for(i = 0; i < u8index; i++)
{
__delay_cycles(500000000/500000); // Wait 1/200000 second
}
gpio1[GPIO_SETDATAOUT] = USR3; // On
for(i = 200; i > u8index; i--)
{
__delay_cycles(500000000/500000); // Wait 1/200000 second
}
}
u8index = u8index + u16FreqCtrl;//PWM speed control
if(u8index > 200)
u8index = 1;
对于需求5):结合需求4)和需求2)的工程,捕捉P9_14端口的输入,进行防抖处理,并对控制步进频率的变量进行切换;
if(~gpio1[SWITCHIN]&P9_14) //if P19_14 low,sw is press
{
u8PressCounter ++;
if(u8PressCounter > ENUM_PRESS_FILTER) //Filter
{
u8PressCounter = 0;
if(u8CurrentSWSts == ENUM_SW_STS_ONE)//switch status
{
u16FreqCtrl = ENUM_FREQ_CTRL_HIGH;
u8CurrentSWSts = ENUM_SW_STS_TWO;
}
else if(u8CurrentSWSts == ENUM_SW_STS_TWO)
{
u16FreqCtrl = ENUM_FREQ_CTRL_LOW;
u8CurrentSWSts = ENUM_SW_STS_ONE;
}
}
}
基于以上软件需求,结合外部电路,完成本次任务。
硬件连接图如下:
任务效果如下描述:
首先呼吸灯慢闪,按下按键后,USR3灯切换为呼吸快闪,再次按下按键后,USR3灯切换为呼吸慢闪;按下一次按键,呼吸灯的频率切换一次。
软件流程图如下:
主体代码如下:
////////////////////////////////////////
// JahgFunPackFinal.pru0.c
// Blinks USR3 USR LED using the PRU with PWM contral,use P9_14 to switch the Blinks Freq
// Wiring: None
// Setup: Turn off the USR LEDs triggers
// See: prugpio.h to see to which ports the USR LEDs are attached
// PRU: Any
// Author: Jahg 20241215 Ver1.0
////////////////////////////////////////
#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table_empty.h"
#include "prugpio.h"
//Just remember that __R30 is for outputs and __R31 is for inputs.
volatile register unsigned int __R30;
volatile register unsigned int __R31;
#define SWITCHIN 0x138/4
#define ENUM_PRESS_FILTER 0x1
#define ENUM_SW_STS_ONE 0x1
#define ENUM_SW_STS_TWO 0x2
#define ENUM_FREQ_CTRL_HIGH 0x30
#define ENUM_FREQ_CTRL_LOW 0x8
void main(void) {
// Points to the two GPIO ports that are used
uint32_t *gpio1 = (uint32_t *)GPIO1;
/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
uint8_t u8index = 255;
uint16_t u16FreqCtrl = 5;
uint8_t i = 0;
uint16_t j = 0;
uint8_t u8CurrentSWSts = 0x1;
uint8_t u8PressCounter = 0x0;
while(1) {
if(~gpio1[SWITCHIN]&P9_14) //if P19_14 low,sw is press
{
u8PressCounter ++;
if(u8PressCounter > ENUM_PRESS_FILTER) //Filter
{
u8PressCounter = 0;
if(u8CurrentSWSts == ENUM_SW_STS_ONE)//switch status
{
u16FreqCtrl = ENUM_FREQ_CTRL_HIGH;
u8CurrentSWSts = ENUM_SW_STS_TWO;
}
else if(u8CurrentSWSts == ENUM_SW_STS_TWO)
{
u16FreqCtrl = ENUM_FREQ_CTRL_LOW;
u8CurrentSWSts = ENUM_SW_STS_ONE;
}
}
}
//呼吸灯频率控制部分
for(j = 0; j < 100; j++)// 100 cycle
{
gpio1[GPIO_CLEARDATAOUT] = USR3; // Turn USR2 LED off
for(i = 0; i < u8index; i++)
{
__delay_cycles(500000000/500000); // Wait 1/200000 second
}
gpio1[GPIO_SETDATAOUT] = USR3; // On
for(i = 200; i > u8index; i--)
{
__delay_cycles(500000000/500000); // Wait 1/200000 second
}
}
u8index = u8index + u16FreqCtrl;//PWM speed control
if(u8index > 200)
u8index = 1;
}
__halt();
}
// Turns off triggers
#pragma DATA_SECTION(init_pins, ".init_pins")
#pragma RETAIN(init_pins)
const char init_pins[] =
"/sys/class/leds/beaglebone:green:usr1/trigger\0none\0" \
"/sys/class/leds/beaglebone:green:usr2/trigger\0none\0" \
"\0\0";
总结:
通过本次任务,熟悉了BBB板卡的设计,查阅了很多资料,了解了BBB板卡的设计目标是为了软硬件爱好者和开发人员的使用,所以开源了很多硬件及软件的资料。虽然使用的Ti芯片很老,但是由于里面集成了PRU,可玩性还是很高的。通过PRU控制的PWM波形,通过示波器观察,波形十分稳定,实现的1ms的PWM波形非常漂亮。BBB的硬件设计也很棒,板卡简洁小巧,丝印标识清晰,做工扎实,对应的硬件资料也十分丰富。同时,板卡的上手非常简单,由于自带了EMMC,收到板卡后立即可以使用,使用USB线接入电脑,通过本地IP地址就可访问,非常方便。比起树莓派来说,虽然性能不及,但是易用性,硬件资料的丰富性都是远远强于树莓派的。