上个学期天津大学的吕卫老师,在他《微处理器系统》课程的实验环节上,让研究生们使用织女星开发板做了一些项目。
本文是其中一份工作,由国际工程师学院,电子与通信工程的徐扬扬和张千依同学共同完成的实验报告,呈现给大家作为参考。
织女星开发板简介
织女星开发板是一款基于无线MCU RV32M1的RISC-V的评估开发板。
RV32M1集成了可工作在2.36GHz到2.48GHz频率范围,支持FSK/GFSK和O-QPSK调制的无线收发器。
RV32M1是一颗异构四核MCU芯片,包括一个RISC-V RI5CY核、一个RISC-V ZERO_RISCY核、一个Arm Cortex-M4F核和一个Cortex-M0+核。
织女星开发板包括主芯片RV32M1、32MHz参考晶振、RF射频电路(包括PCB 天线)、32-Mbit的外部SPI串行Flash和支持标准的Freedom板接口。
www.open-isa.cn提供支持RV32M1的RISC-V核的GNU GCC工具链、SDK软件开发包和其它相关文档和软件的下载链接。
RT-Thread移植步骤
1 | 首先下载RT-Thread官方发布的最新版本并解压到某个目录。 | |
2 | 安装env工具 Env 是 RT-Thread 推出的开发辅助工具,针对基于 RT-Thread 操作系统的项目工程,提供编译构建环境、图形化系统配置及软件包管理功能。其内置的 menuconfig 提供了简单易用的配置剪裁工具,可对内核、组件和软件包进行自由裁剪,使系统以搭积木的方式进行构建。 | |
3 | 安装并使用riscv-embed-gcc工具链(添加环境变量)。 | |
4 | 使用env工具编译项目 | |
a) | 首先进入到工程目录下(bsp目录下找到对应的板级支持包) | |
b) | 设置使用riscv-embed-gcc工具链(这是设置使用自己的GCC工具链) 在我的电脑上就是使用如下命令: set RTT_EXEC_PATH=D:\GNU MCU Eclipse\RISC-V Embedded GCC\8.2.0-2.2-20190521-0004\bin | |
c) | 调试程序 | |
d) | 在env工具命令行输入scons进行编译,编译成功后产生rtthread.elf文件,即是可以烧进板子中的文件。 | |
5 | 使用openocd+gdb连接开发板并进行调试 | |
a) | 首先连接板子和电脑 | |
b) | 打开一个cmd窗口,使用如下指令连接到目标板 openocd -f F:\MCU\kaifabanziliao\Release\rv32m1_sdk_riscv\rv32m1_sdk_riscv\boards\rv32m1_vega\rv32m1_ri5cy.cfg | |
c) | 打开一个新的cmd,进入到之前生成的.elf文件所在目录 | |
d) | 输入如下指令来运行gdb调试 riscv32-unknown-elf-gdb rtthread.elf | |
e) | 输入如下指令来连接gdb到openocd target remote localhost:3333 | |
f) | 输入load命令将二进制文件加载到flash当中去 | |
g) | 打开设备管理器找到串口号如COM3,打开串口调试程序putty将connection type选择成serial,将波特率设置为115200 | |
h) | 输入monitor reset重启一下,就能看到RT-Thread启动的logal信息,如下: |
i) | 输入help,可以看到该系统提供的各种指令 |
j) | 通过env工具可以对软件包进行管理,根据需求进行增减。(RT-Thread官方提供的工具,可以很方便的对系统进行裁剪和应用的添加,更多使用教程参见 https://www.rt-thread.org/document/site/programming-manual/env/env/) |
利用板上LED和按键开发程序
在移植RT-Thread系统后,利用开发板上的LED和按键实现按键对LED开关及颜色的控制。
一、LED及按键使用简介
LED的亮灭控制
织女星开发板上有一个RGB三色LED灯,可以供应用程序作为指示信息使用。还提供了一个红色的LED指示灯(D2),可以用来作为一般的状态指示灯。
下图为这些LED电路图:
LED由VTGT_MCU供电,灯的开关是由Q1和Q2控制。通过Q1和Q2,即使GPIO的电压小于VTGT_MCU,LED灯也可以正常被控制。RGB三色LED灯中的蓝色灯和绿色灯,如果VTGT_MCU供电电压太小,则它们有可能无法点亮。
首先定义LED的管脚,通过查阅开发资料,不同的颜色对应的管脚分别为:
#define LED_BLUE 23
#define LED_GREEN 24
#define LED_RED 25
然后通过RT-Thread系统封装的函数rt_pin_mode()将管脚设置为输出模式:
// 设置管脚为输出模式
rt_pin_mode(LED_BLUE, PIN_MODE_OUTPUT);
接下来通过向管脚写入电平值来控制LED的亮灭。
// 输出低电平,红灯亮
rt_pin_write(LED_RED, PIN_HIGH);
用户按键控制
织女星开发板提供了四个按钮可以完成某些作为人机互动(HMI)操作。开关按钮的电路图如下所示:
SW2提供了一个外部上拉电阻,然后连接到RV32M1的NMI引脚。这使得可以使用这个按钮作为NMI信号或者设备唤醒源,ROM bootloader的启动选项源,或者作为一个通用的输入中断源。
SW3、SW4和SW5可以作为普通输入信号,可以作为中断或唤醒源。使用这些信号时,必须使能这些引脚内部的上拉电阻。
开关的控制原理同LED类似,也是通过:定义管脚,设置管脚模式,检测电平,来判断按键是否按下。
二、程序实现
程序1:LED闪烁程序
首先定义线程体:
在线程体内定义好要进行的操作,比如我在线程体内定义了LED的开关,实现闪烁。
其次通过rt_thread_create()函数来创建线程,并设置好各项参数,
最后将命令导出到控制台,使用
程序2:按键控制
按键控制的原理类似于LED,在线程体内,首先将按键的管脚设置为上拉输入,然后通过另外一个函数rt_pin_read()来检测电平变化,若检测到低电平则按键按下,考虑到人手按键的持续时间,检测到低电平后延时500ms,此时通过向控制台打印信息说明成功,说明按键可以使用了。
程序3:线程间通信
创建两个线程,分别为按键线程和LED线程声明一个信号量,在按键线程中检测到按键按下后,通过信号量告知LED线程点亮LED,从而实现按键控制LED的亮灭和颜色变化。
代码
程序1:
#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
#define LED_BLUE 23
#define LED_GREEN 24
#define LED_RED 25
//static int pin_num;
static void led_thread_entry(void* parameter)
{
//设置管脚为输出模式
rt_pin_mode(LED_BLUE, PIN_MODE_OUTPUT);
//设置管脚为输出模式
rt_pin_mode(LED_GREEN, PIN_MODE_OUTPUT);
//设置管脚为输出模式
rt_pin_mode(LED_RED, PIN_MODE_OUTPUT);
while (1)
{
//红色
//输出低电平,红灯 亮
rt_pin_write(LED_RED, PIN_HIGH);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//输出高电平,红灯 灭
rt_pin_write(LED_RED, PIN_LOW);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//绿色
//输出低电平,绿灯 亮
rt_pin_write(LED_GREEN, PIN_HIGH);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//输出高电平,绿灯 灭
rt_pin_write(LED_GREEN, PIN_LOW);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//蓝色
//输出低电平,蓝灯 亮
rt_pin_write(LED_BLUE, PIN_HIGH);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//输出高电平,蓝灯 灭
rt_pin_write(LED_BLUE, PIN_LOW);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//黄色=红+绿
//输出低电平,红灯 亮
rt_pin_write(LED_RED, PIN_HIGH);
//输出低电平,绿灯 亮
rt_pin_write(LED_GREEN, PIN_HIGH);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//输出高电平,红灯 灭
rt_pin_write(LED_RED, PIN_LOW);
//输出高电平,绿灯 灭
rt_pin_write(LED_GREEN, PIN_LOW);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//青色=蓝+绿
//输出低电平,蓝灯 亮
rt_pin_write(LED_BLUE, PIN_HIGH);
//输出低电平,绿灯 亮
rt_pin_write(LED_GREEN, PIN_HIGH);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//输出高电平,蓝灯 灭
rt_pin_write(LED_BLUE, PIN_LOW);
//输出高电平,绿灯 灭
rt_pin_write(LED_GREEN, PIN_LOW);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//品红色=蓝+红
//输出低电平,蓝灯 亮
rt_pin_write(LED_BLUE, PIN_HIGH);
//输出低电平,红灯 亮
rt_pin_write(LED_RED, PIN_HIGH);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
//输出高电平,蓝灯 灭
rt_pin_write(LED_BLUE, PIN_LOW);
//输出高电平,红灯 灭
rt_pin_write(LED_RED, PIN_LOW);
//挂起 500ms
rt_thread_delay(rt_tick_from_millisecond(500));
}
}
static int led_sample(void* parameter)
{
rt_thread_t tid;//线程句柄
rt_err_t ret = RT_EOK;
/*创建led线程*/
tid = rt_thread_create("led",
led_thread_entry,
RT_NULL,
1024,
3,
10);
/*创建成功则启动线程*/
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
ret=RT_ERROR;
}
return ret;
}
MSH_CMD_EXPORT(led_sample, led sample);
程序2:
#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
#define LED_BLUE 23
#define LED_GREEN 24
#define LED_RED 25
#define LED_YELLOW 26
#define LED_CHING 27
#define LED_MAGENTA 28
#define LED_WHITE 29
#define KEY_PIN 1
static void key_thread_entry(void* parameter)
{
//SW2设置上拉输入
rt_pin_mode(KEY_PIN, PIN_MODE_INPUT_PULLUP);
//设置LED输入
rt_pin_mode(LED_BLUE, PIN_MODE_OUTPUT);
rt_pin_mode(LED_GREEN, PIN_MODE_OUTPUT);
rt_pin_mode(LED_RED, PIN_MODE_OUTPUT);
//定义FLAG用于切换按键效果
static rt_uint8_t FLAG = PIN_HIGH;
static rt_uint8_t color = 23;
static int count = 0;
while (1)
{
if (rt_pin_read(KEY_PIN) == PIN_LOW)
{
rt_thread_mdelay(300);
rt_kprintf("检测到按键按下\n");
count = count + 1;
switch(color){
case LED_BLUE:rt_pin_write(LED_BLUE, FLAG);break;
case LED_GREEN:rt_pin_write(LED_GREEN, FLAG);break;
case LED_RED:rt_pin_write(LED_RED, FLAG);break;
case LED_YELLOW:rt_pin_write(LED_RED, FLAG),rt_pin_write(LED_GREEN, FLAG);break;
case LED_CHING:rt_pin_write(LED_BLUE, FLAG),rt_pin_write(LED_GREEN, FLAG);break;
case LED_MAGENTA:rt_pin_write(LED_RED, FLAG),rt_pin_write(LED_BLUE, FLAG);break;
case LED_WHITE:rt_pin_write(LED_RED, FLAG),rt_pin_write(LED_GREEN, FLAG),rt_pin_write(LED_BLUE,FLAG);break;
//default:rt_pin_write(LED_BLUE, FLAG);
}
if (count%2 == 0)//每按两次实现一种颜色的亮灭,之后换一种颜色
{
color = color + 1;
if (color > 29)
{
color = 23;
}
}
//改变下一次按键的作用
if(FLAG == PIN_HIGH)
{
rt_kprintf("亮灯!\n");
FLAG = PIN_LOW;
}else
{
rt_kprintf("灭灯!\n");
FLAG = PIN_HIGH;
}
rt_kprintf("********************************\n");
}
}
//挂起 10ms
//rt_thread_delay(rt_tick_from_millisecond(10));
}
static int key_sample(void* parameter)
{
rt_thread_t tid;//线程句柄
rt_err_t ret = RT_EOK;
/*创建led线程*/
tid = rt_thread_create("key",
key_thread_entry,
RT_NULL,
1024,
3,
10);
/*创建成功则启动线程*/
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
ret=RT_ERROR;
}
return ret;
}
MSH_CMD_EXPORT(key_sample, key sample);
程序3:
#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
#define LED_BLUE 23
#define LED_GREEN 24
#define LED_RED 25
#define LED_YELLOW 26
#define LED_CHING 27
#define LED_MAGENTA 28
#define LED_WHITE 29
#define KEY_PIN 1
#define THREAD_PRIORITY 25
#define THREAD_TIMESLICE 5
/* 指向信号量的指针 */
static rt_sem_t dynamic_sem = RT_NULL;
//定义计数决定开关
static int count = 0;
//定义起始颜色为蓝色
static rt_uint8_t color = 23;
ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
static void rt_thread1_entry(void *parameter)
{
//SW2设置上拉输入
rt_pin_mode(KEY_PIN, PIN_MODE_INPUT_PULLUP);
while (1)
{
if (rt_pin_read(KEY_PIN) == PIN_LOW)
{
//延时
rt_thread_mdelay(300);
rt_kprintf("按键按下,释放信号量.\n");
//释放信号量
rt_sem_release(dynamic_sem);
}
}
}
ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
static void rt_thread2_entry(void *parameter)
{
//定义电平标志
static rt_uint8_t FLAG = PIN_HIGH;
static rt_err_t result;
//设置LED输入模式
rt_pin_mode(LED_BLUE, PIN_MODE_OUTPUT);
rt_pin_mode(LED_GREEN, PIN_MODE_OUTPUT);
rt_pin_mode(LED_RED, PIN_MODE_OUTPUT);
while (1)
{
/* 永久方式等待信号量,获取到信号量,则执行操作 */
result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
rt_kprintf("thread2 take a dynamic semaphore, failed!.\n");
rt_sem_delete(dynamic_sem);
return;
}
else
{
rt_kprintf("LED线程拿到信号量.做出操作\n");
switch(color){
case LED_BLUE:rt_pin_write(LED_BLUE, FLAG);break;
case LED_GREEN:rt_pin_write(LED_GREEN, FLAG);break;
case LED_RED:rt_pin_write(LED_RED, FLAG);break;
case LED_YELLOW:rt_pin_write(LED_RED, FLAG),rt_pin_write(LED_GREEN, FLAG);break;
case LED_CHING:rt_pin_write(LED_BLUE, FLAG),rt_pin_write(LED_GREEN, FLAG);break;
case LED_MAGENTA:rt_pin_write(LED_RED, FLAG),rt_pin_write(LED_BLUE, FLAG);break;
case LED_WHITE:rt_pin_write(LED_RED, FLAG),rt_pin_write(LED_GREEN, FLAG),rt_pin_write(LED_BLUE,FLAG);break;
//default:rt_pin_write(LED_BLUE, FLAG);
}
count = count + 1;
if (count%2 == 0)//每按两次实现一种颜色的亮灭,之后换一种颜色
{
color = color + 1;
if (color > 29)
{
color = 23;
}
}
//改变下一次按键的作用
if(FLAG == PIN_HIGH)
{
rt_kprintf("亮灯!\n");
FLAG = PIN_LOW;
}else
{
rt_kprintf("灭灯!\n");
FLAG = PIN_HIGH;
}
rt_kprintf("********************************\n");
}
}
}
/* 信号量示例的初始化 */
int semaphore_sample()
{
/* 创建一个动态信号量,初始值是0 */
dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
if (dynamic_sem == RT_NULL)
{
rt_kprintf("create dynamic semaphore failed.\n");
return -1;
}
else
{
rt_kprintf("create done. dynamic semaphore value = 0.\n");
}
rt_thread_init(&thread1,
"thread1",
rt_thread1_entry,
RT_NULL,
&thread1_stack[0],
sizeof(thread1_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread2,
"thread2",
rt_thread2_entry,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(semaphore_sample, semaphore sample);
参考文献
https://www.rt-thread.org/document/site
https://github.com/open-isa-cn/vega-lite/tree/master/应用笔记
3.硬件工程师VS软件工程师:我学得这么难,为什么薪水没你多?
免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。