基于BeagleBone Black PRU的呼吸灯设计
该项目使用了BeagleBone Black开发板的PRU,实现了通过按键控制呼吸灯的设计,它的主要功能为:基于BeagleBone Black的PRU模块,实现一个呼吸灯效果,同时可以通过按键控制呼吸的的显示效果。
标签
嵌入式系统
Funpack活动
开发板
呼吸灯
PRU
相伴左右
更新2025-01-15
126

1、系统更新

使用USB连接连接上电脑之后,可以在电脑 设备和驱动器 位置看到一个新的盘符,进入到里面打开文件 START.HTM,按里面步骤把板卡系统更新为最新版本.

2、连接板卡并打开Visual Studio Code

​更新系统之后,根据 Basics — BeagleBoard Documentation 里面指令

sudo systemctl start bb-code-server.service

打开板卡VSCode服务.之后即可正常访问VSCode

1729852342827(1).png

备注:命令需要打开ssh登录之后配置,连接上ssh之后会提示用户名和登录密码.

3, 通过网线使板卡连接互联网

参考链接 Beyond the Basics — BeagleBoard Documentation

4、获取 PRU示例代码

参考链接 Getting Example Code,并根据链接内容,查看是否能正常运行

5、功能实现

1)、硬件连接

硬件连接示意图如下

e77542fa256834e5ca7bbd3f3b663ed.png


其中LED串联一个电阻连接至P9_30引脚,KEY通过一个下拉电阻连接至P9_27引脚

2)、程序框图

程序框图如下所示,基本为线性工作方式,每个循环去判断按键状态,并更新呼吸灯频率

1735815065454.png

3)、测试连接

编写input_setup.sh文件,配置PRU输入输出引脚(呼吸灯和按键)

#!/bin/bash
#
export TARGET=input.pru0
echo TARGET=$TARGET


# Configure the PRU pins based on which Beagle is running
echo " Black Found"
config-pin P9_30 pruout
config-pin -q P9_30
config-pin P9_27 pruin
config-pin -q P9_27

执行指令 source input_setup.sh,显示如下信息则配置正确

Current mode for P9_30 is:     pruout
Current mode for P9_30 is: pruout
Current mode for P9_27 is: pruin
Current mode for P9_27 is: pruin


以上代码将P9_30配置为PRU输出引脚用以连接LED灯,P9_27配置为PRU输入引脚连接按键

通过如下代码input_pru0.c将KEY和LED连接,使用指令 make TARGET=input_pru0检测硬件是否正常

#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table_empty.h"

volatile register uint32_t __R30;
volatile register uint32_t __R31;

void main(void)
{
uint32_t led;
uint32_t sw;

/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

led = (1<<2); // P9_30
sw = (1<<5); // P9_11

while (1) {
if((__R31&sw) == sw) {
__R30 |= led; // Turn on LED
} else
__R30 &= ~led; // Turn off LED
}
}

4)、实现呼吸灯

一般呼吸灯的实现采用逐渐调整PWM占空比实现,但在BeagleBone 的PRU简单教材中没有发现关于PWM外设的教材,所以直接通过定时调整高低电平的方式实现呼吸灯

定义引脚宏定义

#define P9_30   (1<<2)
#define P9_27 (1<<5)

#define LED P9_30
#define KEY P9_27

a、创建一个延时函数,用作PWM延时

void delay_us(uint32_t us){
uint32_t i;
for(i=0; i<us; i++){
__delay_cycles(1000/5);
}
}

b、创建一个函数,实现一个PWM周期输出

/**
*pin:pwm的输出引脚
* freq: PWM的运行频率
*duuty:PWM占空比
*/
void showPwm(uint32_t pin, float freq, float duty)
{
//由于上面软件定时最小间隔为1us,这里定义1秒为多少us
uint32_t oneSecWaitTimes = (uint32_t)1000000; //1秒有1000 000微妙
//根据设定的PWM频率计算PWM时间周期,单位 us
uint32_t oneCycleTimes = (uint32_t)(oneSecWaitTimes / freq);
//根据占空比计算PWM高电平时间,单位us
uint32_t heightLevelTimes = (uint32_t)(oneCycleTimes * duty);
//一个PWM内低电平时长,单位us
uint32_t lowLevelTimes ;

//计算低电平时长 单位us
if(heightLevelTimes >= oneCycleTimes){
lowLevelTimes = 0;
}else if(heightLevelTimes <= 0){
lowLevelTimes = oneCycleTimes;
}else{
lowLevelTimes = oneCycleTimes - heightLevelTimes;
}

__R30 |= pin; // Turn on LED
delay_us(heightLevelTimes);
__R30 &= ~ pin; // Turn off LED
delay_us(lowLevelTimes);
}

c、创建一个按键读取函数,获取按键的输入状态

/**
*读取按键的状态,由于函数调用间隔跟pwm输出频率有关,所以此处需要输入pwm频率
*这里只检测按键是否按下,不考虑长按,双击等事件
*pin:key按键输入引脚
* freq: PWM的运行频率
*/
uint8_t key_scan(uint32_t pin, float freq)
{
static float pinPressedTimes = 0;
static float pinRelssedTimes = 0;
static uint8_t pressedFlag = 0;
//计算key_scan函数调用的间隔
float intervalTime = 1/freq;

if((__R31&pin) == pin) { //按键按下
pinRelssedTimes = 0;
pinPressedTimes += intervalTime;
//按键按下超过0.1S,置位按下标志
if((pinPressedTimes > 0.1) && (pressedFlag == 0)){
pressedFlag = 1;
}
}else{ //按键松开
pinPressedTimes = 0;
pinRelssedTimes += intervalTime;
//按键松开0.1S且按键按下标志为1,返回按键按下标志,这种方式只有在按键松开时才会返回按键按下事件
if((pressedFlag == 1) && (pinRelssedTimes > 0.1)){
pressedFlag = 0;
return 1;
}
}
return 0;
}

d、编写运行逻辑

void main(void)
{
float pwmFreq = 100.0; //PWM频率
float breathFreq = 0.5; //呼吸灯频率
float incDuty = 2*breathFreq / pwmFreq; //PWM占空比变化值
float pwmDuty = 0; //PWM初始占空比
uint8_t direction = 0; //呼吸灯方向
uint8_t keyState = 0; //按键状态

/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

while (1) {
keyState = key_scan(KEY, pwmFreq); //获取按键状态

if(keyState == 1){ //按键按下
//处理按键信息
breathFreq *= 2; //呼吸灯呼吸频率*2
if(breathFreq > 10){
breathFreq = 0.2;
}
incDuty = 2*breathFreq / pwmFreq; //刷新占空比增量
}

if(direction == 0){ //逐渐变亮
pwmDuty += incDuty;
if(pwmDuty > 1){ //占空比达到最大,改变方向
pwmDuty = 1;
direction = 1;
}
}else{ //逐渐变暗
pwmDuty -= incDuty;
if(pwmDuty < 0){ //占空比达到最小,改变方向
pwmDuty = 0;
direction = 0;
}
}
showPwm(LED, pwmFreq,pwmDuty); //pwm输出
}
}

心得体会

由于之前基本都没有接触过linux,在最开始没有了解PRU时做了很多心理准备,中间拖了很长时间,后面发现如果只是简单实现功能,不需要linux也可以实现,减少了很多压力,很多事情还是需要上手才知道具体难度。


附件下载
config.sh
PRU 引脚配置脚本
pwm_pru.c
PRU呼吸灯文件
团队介绍
个人项目
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号