[TOC]

AB32开发板测评:RGB彩灯

3.5号的时候参加了RT-Thread社区的一个活动,报名了中科蓝讯的一款开发板的测评,有幸入选成为第一批测评人员,申请了一块中科蓝讯的开发板AB32VG1,测评任务是GPIO测试,作为点灯老手,本次测评准备使用矩阵键盘输入控制信号,GPIO模拟PWM的方式,输入三路PWM来改变RGB彩灯的颜色,文章的代码链接都发布到了文章末尾

一、初始准备

1.硬件平台

AB32VG1开发板

20210318170127

芯片介绍:

CPU:AB5301A;(LQFP48 封装,主频 120M,片上集成 RAM 192K, flash 8 Mbit,ADC,PWM,USB,UART,IIC 等资源)

Flash和RAM真大,感觉专门为了RT-Thread配置的,适合上RTT完整版

2.软件平台

RT-Thread Stdio软件平台

Downloader下载平台

20210318172331

二、操作步骤

1.RTT环境生成

  • 新建RTT项目

新建RTT控件如下

20210209213346

选择基于开发板的项目,填写工程名字,选择我们使用到的开发板(AB32VG1),调试器我们随便选,下载方式不是通过此处下载

20210318180626

注意:如果第一次使用RISC-V芯片需要安装工具链,在SDK管理器中下载工具链

20210318193859

然右击项目名称,进入属性

20210318194757

找到MCU->RISC-V ToolchainsPat ,配置Tool的环境,在软件安装位置下面的路径中

1
软件安装位置\RT-ThreadStudio\repo\Extract\ToolChain_Support_Packages\RISC-V\RISC-V-GCC\10.1.0\bin

20210318195006

工程新建后左边的项目资源管理器会显示我们的工程,我们把他展开,并且编译一下,编译结果如下

20210318195444

  • 新建程序文件

新建一个Hardware文件夹,建立一个pwm.c和.h文件,再建立一个key_board.c和.h文件,建立后如下

20210318201808

2.RTT程序编写

  • 程序源码

创建之后分别写入头文件和.c文件的代码

PWM文件

头文件代码简单理解,不用多说,c语言基本格式

1
2
3
4
5
6
7
8
#ifndef PWM_H__
#define PWM_H__
//GPIO模拟PWM的GPIO初始化
void pwm_init(void);
//GPIO模拟PWM的实体
void pwm_entry(void);

#endif

.c文件逻辑如下,我们点亮LED是对IO口进行操作,在RTT里面,IO口的在drv_gpio.c内定义为引脚,我们在drv_gpio.c里面找到对应引脚,在开发板原理图上RGB引脚对应IO口如下:

20210318203236

PE1—R / PE4—G / PA2—B

找到对应的GPIO口之后,我们创建一个RGB_GPIO_INIT初始化函数,对使用到的三个RGB的GPIO口进行初始化,GPIO初始化的步骤很简单,因为是基于板载工程,创建首先获取板载资源IO口,这里是R、G、B三个口,获取后返回一个GPIO对象,对对象进行操作,配置模式,在之后的读取与写入也是对对象进行操作,初始化GPIO的同时,也创建一个PWM产生线程,初始化代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//GPIO模拟PWM的GPIO初始化
void pwm_init(void)
{
rt_thread_t tid;
rt_err_t ret = RT_EOK;
//返回句柄
R = rt_pin_get(LED_R);
G = rt_pin_get(LED_G);
B = rt_pin_get(LED_B);

/* 设置PIN脚模式为输出 */
rt_pin_mode(R, PIN_MODE_OUTPUT);
rt_pin_mode(G, PIN_MODE_OUTPUT);
rt_pin_mode(B, PIN_MODE_OUTPUT);

rt_pin_write(R, PIN_HIGH);
rt_pin_write(G, PIN_HIGH);
rt_pin_write(B, PIN_HIGH);

tid = rt_thread_create("pwm_rgb",
pwm_entry,
RT_NULL,
512,
10,
20);
if (tid != RT_NULL)
{
//创建线程
rt_thread_startup(tid);
}
else
{
ret = RT_ERROR;
}
}

GPIO初始化完成后,我们对三个GPIO口编写模拟PWM线程函数(非寄存器比较输出),我先分享一下GPIO模拟PWM的概念,PWM的含义:一般指脉冲宽度调制,实际上就是一个周期方波,其中高电平占据整个周期的比例叫做占空比,我们先设置一个传入当前周期计数数目,用于与整个周期计数长度进行比较,当当前计数周期数目小于我们设定的比较值时,GPIO输出高电平,否则输出低电平,我们单独设置一个线程,线程内部延时10ms,每次执行对一个当前进行计数周期+1,大于最大周期则复位,继续循环,函数主体如下,我们只要改变三个传入的比较值就可以改变PWM,从而形成RGB灯光效果的改变!

PWM线程主体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//GPIO模拟PWM的实体
void pwm_entry(void* p)
{
uint8_t count;
while(1)
{
//设定脉宽200ms
count++;
count %=10;
rt_thread_mdelay(1);
//模拟pwm比较
//红色的pwm输出
if(count>a)
{
rt_pin_write(R, PIN_LOW);
}
else {
rt_pin_write(R, PIN_HIGH);
}
//绿色的PWM输出
if(count>b)
{
rt_pin_write(G, PIN_LOW);
}
else {
rt_pin_write(G, PIN_HIGH);
}
//蓝色的pwm输出
if(count>b)
{
rt_pin_write(B, PIN_LOW);
}
else
{
rt_pin_write(B, PIN_HIGH);
}
}
}

以上两个函数用到的变量的定义

1
2
3
4
5
6
7
//使用板载资源
#define LED_R "PE.1"
#define LED_G "PE.4"
#define LED_B "PA.2"

uint8_t R,G,B; //GPIO口句柄
uint8_t a,b,c; //比较值

key_board.c文件

RGB驱动编写好了,下面我们就是编写按键的驱动,这里RGB彩灯有三个通道,每个通道都需要一个数值增加按键和数值减少按键,蓝讯板子上没有如此多的按键,所以我焊接外扩了六个按键(本来想使用矩阵键盘的,但奈何我的矩阵键盘模块丢了,所以就焊接了6个)原理图接口如下,按键为按下产生上升沿

20210324104401

实物图如下:

_795135468_IMG_20210323_232907_1616513348000_wifi

功能图:

20210324104108

按键程序的编写有两种方式:第一种是一直死循环扫描读取对应的GPIO电平,当按键按下时程序执行,第二种则是通过外部中断来实现,当按键按下,GPIO口电平变换,GPIO口关联的外部中断触发,在中断函数里面置位按键触发标志,然后主函数内处理程序

两个方法各有优势:方式一简单但消耗CPU运行资源,方式二复杂,但资源占用小,这里我使用的是方式一(简单)

编写key_board_init()函数,用于初始化各个IO口为输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uint8_t key1,key2,key3,key4,key5,key6;
uint8_t key_pres;
void key_board_init(void)
{
key1= rt_pin_get("PF.1");
key2= rt_pin_get("PA.6");
key3= rt_pin_get("PA.5");
key4= rt_pin_get("PF.0");
key5= rt_pin_get("PA.1");
key6= rt_pin_get("PA.0");
// 下拉输入
rt_pin_mode(key1, PIN_MODE_INPUT_PULLDOWN );
rt_pin_mode(key2, PIN_MODE_INPUT_PULLDOWN );
rt_pin_mode(key3, PIN_MODE_INPUT_PULLDOWN );
rt_pin_mode(key4, PIN_MODE_INPUT_PULLDOWN );
rt_pin_mode(key5, PIN_MODE_INPUT_PULLDOWN );
rt_pin_mode(key6, PIN_MODE_INPUT_PULLDOWN );
}

编写key_Scan函数,用于读取返回按键值,这里设置了一个key_pres用于保护,禁止连续按,按一次只生效一次,软件延时消抖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
uint8_t key_scan(void)
{
if(key_pres==0)
{
key_pres=1;
if(rt_pin_read(key1)==1)
{
rt_thread_mdelay(30);//消抖
if(rt_pin_read(key1)==1)
{
return 1;
}
}
if(rt_pin_read(key2)==1)
{
rt_thread_mdelay(30);
if(rt_pin_read(key2)==1)
{
return 2;
}
}
if(rt_pin_read(key3)==1)
{
rt_thread_mdelay(30);
if(rt_pin_read(key3)==1)
{
return 3;
}
}
if(rt_pin_read(key4)==1)
{
rt_thread_mdelay(30);
if(rt_pin_read(key4)==1)
{
return 4;
}
}
if(rt_pin_read(key5)==1)
{
rt_thread_mdelay(30);
if(rt_pin_read(key5)==1)
{
return 5;
}
}
if(rt_pin_read(key6)==1)
{
rt_thread_mdelay(30);
if(rt_pin_read(key6)==1)
{
return 6;
}
}
}else {
if(rt_pin_read(key1)|rt_pin_read(key2)|rt_pin_read(key3)|rt_pin_read(key4)|rt_pin_read(key5)|rt_pin_read(key6))
{
key_pres=0;
}
}
return 0;
}

主线程内对按键结果的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int main(void)
{
uint8_t key;
key_board_init();
pwm_init();
while(1)
{
key=key_scan();
if(key==1)
a++;
else if(key==2)
a--;
else if(key==3)
b++;
else if(key==4)
b--;
else if(key==5)
c++;
else if(key==6)
c--;

if(a>9)
a=9;
else if(a<1)
a=1;
if(b>9)
b=9;
else if(b<1)
b=1;
if(c>9)
c=9;
else if(c<1)
c=1;
rt_thread_mdelay(10);
}
return 0;
}

3.程序下载,观察现象

代码编写完成,点击小锤子编译,下图编译无报错警告,功能实现

20210324081526

编译完成,打开Downloaded下载器(打开前需要先安装串口驱动)

20210324092249

扫描串口,点击开始后,按一下板子上复位按键下载程序

20210324103700

流水灯现象视频

三、心得

前几天事件比较紧,没有时间花费在板子上研究,这两天才开始研究一下,因为做的GPIO测评,难度也不高,没花多久就完成了,使用的RTT-STUDIO进行开发,开发流程也很简单,没有使用控制台进行调试,有个逻辑设计错了好一会才发现过来,希望以后控制加入在线仿真功能,让调试更加舒服

四、相关链接

github源码

Biliblili链接

个人网页链接

wechat