Funpack3-5 使用BeagleBone® Black开发板通过PRU实现呼吸灯,并通过按键切换呼吸频率
该项目使用了C语言和PRU,实现了呼吸灯和按键切换频率的设计,它的主要功能为:基于beaglebone black开发板,使用PRU输出PWM波实现呼吸灯,并使用PRU读取按键输入,切换呼吸灯呼吸频率。
标签
Funpack活动
呼吸灯
PRU
linux系统
am3358
57SSG
更新2025-01-15
7

1.任务

我选择的活动任务是板卡一BeagleBone® Black的任务1

1.1任务需求

点灯!使用PRU控制一个LED实现呼吸灯,并且使用一个按键按下后切换闪烁的速度.

1.2 完成的功能

使用PRU模块读取按键输入引脚,并使用定时器消抖,完成按键按下和松开识别.当按键被按下时, 循环切换呼吸灯闪烁

频率.总共有3种呼吸周期,分别是400ms、800ms、1200ms.

2.实现思路

2.1软件思路

使用PRU控制IO口输出PWM波,驱动LED。PWM有两个参数频率和占空比。

其中频率影响LED的闪烁频率,若LED的闪烁频率太低,则人眼可以观察出来。本程序中,通过在while循环中使

库函数__delay_cycles,实现获取10us轮询周期。占空比从0到100, 一个PWM周期为1ms。 闪烁频率达1000Hz。

PWM波的占空比影响LED的亮度。 当占空比达到100时,此时LED最亮;占空比为0时,此时LED熄灭。

呼吸灯就是LED的亮度周期性的增加和减小, 循环往复。因此需要通过修改PWM波的占空比来控制LED亮度的周期

性增加和减小。也就是周期性的增加和减小PWM波的占空比。 这个占空比改变的周期也就是呼吸灯的呼吸周期。

2.2程序实现流程图

image.png

2.2硬件思路

查看BeagleBone Cookbook的Displays and Other Outputs部分,了解到IO口的驱动能力在4~6mA之间,满足点灯的电

流需求, 可以直接通过引脚串联电阻和LED来完成LED的驱动.

根据我购买的LED的参考电压(1.8V~2.0V)和电流(20mA),得到LED的可能最小电阻R1=1.8V/20mA = 90Ω.这个最小电阻是避免与LED串联的电阻太小,导致输出功率大于IO口的额定输出功率,从而导致损坏.通过计算得到IO能够接受的最小电阻为R2=3.3V/4mA=825欧姆.因此将与LED串联的电位器设为825-90=735欧姆,将驱动LED的引脚设为高电平后然后缓慢调整电位器电阻,直到LED被点亮.调整后电位器的电阻为670欧姆,流过LED的电流为2mA(能够明显区分点亮和熄灭).

选择P8_12作为PWM信号输出引脚、P8_16作为按键信号输出引脚、P8_11作为占空比修改信号输出.

3.代码实现

3.1变量定义

	/* 引脚端口1,用于没有外界LED时,观察呼吸灯现象 */
uint32_t* gpio1 = (uint32_t*)GPIO1;
/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port 需要开启,不然可能会导致PRU停止 */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
/* PWM信号输出引脚在R30寄存器中的位置 */
uint32_t pwmout = P8_12;
/* 占空比修改时输出信号,用于调试 */
uint32_t cycleout = P8_11;
/* 按键输入引脚在R31寄存器中的位置 */
uint32_t keyin = P8_16;

uint8_t i;
/* 当前PWM占空比 */
int8_t duty = 50;
/* 单次占空比修改值 */
int8_t step = 1;
uint32_t cnt = 0;
/* 占空比修改间隔,单位ms */
uint8_t breatheInterval = 2;

/* 按下按键计数,用于消除抖动,单位ms */
uint32_t duration = 0;
/* 当前按下按键状态 */
bool pressState = FALSE;
/* 1ms之前的按下状态 */
bool lastPressState = FALSE;

3.2生成1000Hz频率PWM波

		/* 1ms */
for (i = 0; i < 100; i++)
{
/* duty为占空比 */
if (i < duty)
{
__R30 |= pwmout; // 设置PWM输出引脚为高电平
gpio1[GPIO_CLEARDATAOUT] = USR3;
}
else
{
__R30 &= ~pwmout; // 设置PWM输出引脚为低电平
gpio1[GPIO_SETDATAOUT] = USR3; // The the USR3 LED on
}
/* 延时10us */
delay_us(10);
}

3.3修改PWM波占空比

		cnt++;
/* breatheInterval为占空比修改间隔,单位ms */
if (cnt >= breatheInterval)
{
__R30 ^= cycleout; /* 每次修改占空比时,反转cycleout对应的引脚 */
cnt = 0;
duty += step; /* step为占空比修改值 */
if ((duty == 100) || (duty == 0))
{
step *= -1;
}
}

3.4实现按下按键,切换LED呼吸频率

		/* keyin是按键输入引脚在R31寄存器中的位置 */
if ((__R31 & keyin))
{
duration++;
/* 按键消抖, 按下按键大于10ms,才算真正按下按键 */
if ((duration >= 10) && (pressState != TRUE))
{
pressState = TRUE;
}
/* when duration is 10, then clear it */
duration %= 10;
}
else
{
pressState = FALSE;
duration = 0;
}
/* 按下按键时,才切换呼吸频率 */
if ((lastPressState == FALSE) && (pressState == TRUE))
{
/* mod the interval of changing duty */
breatheInterval %= 6;
breatheInterval += 2;
}
lastPressState = pressState;

3.5配置PRU引脚

#!/bin/bash

export TARGET=hello.pru0

echo TARGET=$TARGET
# 使用P8_12作为PWM输出引脚
config-pin P8_12 pruout
config-pin -q P8_12

# 使用P8_11指示占空比修改
config-pin P8_11 pruout
config-pin -q P8_11

#使用P8_16作为按键输入
config-pin P8_16 pruin
config-pin -q P8_16

4.心得体悟和遇到的困难

4.1心得体悟

参加这次活动,让我知道了一种系统的实现方法,使得系统同时具有linux的灵活性和微处理器的实时性,那就是在linux

系统中引入PRU.RPU可以独立运行,而不受linux系统调度的影响(在linux系统关闭后,也能工作),从而就弥补了linux系统由于调度算法在实时性方面的缺点.使得在一些对实时性要求的工作场景,也能使用linux系统.

4.2遇到的困难

其中遇到的最大的困难就是PRU程序中不能使用类似printf的函数,直接将调试信息输出到终端.因此在调试的时候,我

就添加了一些输出信号,来辅助调试.还有就是使用beaglebong black官方文档中提到的simpPRU死活不能运行,因此我才选择了文档中所示的编写C文件来实现功能.


附件下载
am335x-pru0-fw
code.zip
团队介绍
一名毕业工作一年的人
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号