基于RT-Thread的智能小车开发实践
基于RT-Thread的智能小车开发实战
目录
任务四:按键控制LED灯闪烁和停止(学习使用信号量进行线程同步) 4
任务七: 小车行驶控制(学习BSP配置方法与PWM设备使用) 8
任务一 实现LED灯闪烁
1、新建工程,编译,测试工程
参考教材P17-22任务实施
2、在aplication目录新建文件led.c,led.h
led.c:
#include <rtthread.h>
#define DBG_TAG "led"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <rtdevice.h>
#include <drv_common.h>
#define LED1 GET_PIN(D,8)
int flash = 1;
int led_flash()
{
rt_pin_mode(LED1, PIN_MODE_OUTPUT);
while(1)
{
if(flash)
{
rt_pin_write(LED1, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED1, PIN_LOW);
rt_thread_mdelay(500);
}
}
return 0;
}
led.h:
#ifndef APPLICATIONS_LED_H_
#define APPLICATIONS_LED_H_
int led_flash();
#endif /* APPLICATIONS_LED_H_ */
main.c
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "led.h"
int main(void)
{
led_flash();
return RT_EOK;
}
任务二:增加按键识别代码
1.在aplication目录新建文件key.c,key.h
代码如下:
key.c:
#include <rtthread.h>
#define DBG_TAG "key"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <rtdevice.h>
#include <drv_common.h>
#define KEY1 GET_PIN(A,1)
void key_scan()
{
rt_pin_mode(KEY1, PIN_MODE_INPUT_PULLUP);
while(1)
{
if(rt_pin_read(KEY1)==PIN_LOW)
{
rt_thread_mdelay(200);
if(rt_pin_read(KEY1)==PIN_LOW){
LOG_D("down");
}
}
rt_thread_mdelay(100);
}
}
key.h:
#ifndef APPLICATIONS_KEY_H_
#define APPLICATIONS_KEY_H_
void key_scan();
#endif /* APPLICATIONS_KEY_H_ */
2.在main.c中加入函数调用:
int main(void)
{
key_scan();
led_flash();
return RT_EOK;
}
存在问题,两个任务不能同时运行。
任务三 使用线程解决多任务运行问题
1.在led.c文件尾增加以下代码:
int led_thread()
{
rt_thread_t tid;
tid = rt_thread_create("led", led_flash, RT_NULL, 1024, 20, 10);//创建线程
rt_thread_startup(tid);//启动线程
return RT_EOK;
}
INIT_APP_EXPORT(led_thread);
2.在main.c中删除对led_flash函数的调用。
3.重新编译运行,可以看到LED灯闪烁,同时按键可以识别,ps命令查看系统中增加了led线程,如图:

4.用同样的方法,把新建一个线程专门用于按键 识别
在key.c中增加以下代码,同时删除main.c中的函数调用。
int key_thread()
{
rt_thread_t tid;
tid =rt_thread_create("key", key_scan, RT_NULL, 1024, 20, 10);
rt_thread_startup(tid);
return RT_EOK;
}
INIT_APP_EXPORT(key_thread);
任务四:按键控制LED灯闪烁和停止(学习使用信号量进行线程同步)
1.在led.c中增加以下代码
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <rtdevice.h>
#include <drv_common.h>
#define LED1 GET_PIN(D,8)
int flash = 1;
rt_sem_t led_sem=RT_NULL;
void led_switch()
{
flash = !flash;
rt_sem_release(led_sem);
}
int led_flash()
{
led_sem = rt_sem_create("led", 0, RT_IPC_FLAG_PRIO);
rt_pin_mode(LED1, PIN_MODE_OUTPUT);
while(1)
{
if(flash)
{
rt_pin_write(LED1, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED1, PIN_LOW);
rt_thread_mdelay(500);
}
else{
rt_sem_take(led_sem, RT_WAITING_FOREVER);
}
}
return 0;
}
2.在led.h中添加函数声明
#ifndef APPLICATIONS_LED_H_
#define APPLICATIONS_LED_H_
int led_flash();
void led_switch();
#endif /* APPLICATIONS_LED_H_ */
3.在key.c中调用切换函数
#include <rtdevice.h>
#include <drv_common.h>
#include "led.h"
#define KEY1 GET_PIN(A,1)
void key_scan()
{
rt_pin_mode(KEY1, PIN_MODE_INPUT_PULLUP);
while(1)
{
if(rt_pin_read(KEY1)==PIN_LOW)
{
rt_thread_mdelay(200);
if(rt_pin_read(KEY1)==PIN_LOW){
LOG_D("down");
led_switch();
}
}
rt_thread_mdelay(100);
}
}
任务五 使用中断方法检测按键动作
1.在key.c中添加以下代码:
void key_cb()
{
LOG_D("down");
led_switch();
}
void key_int()
{
rt_pin_mode(KEY1, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(KEY1, PIN_IRQ_MODE_FALLING, key_cb, RT_NULL);
rt_pin_irq_enable(KEY1, PIN_IRQ_ENABLE);
}
//INIT_APP_EXPORT(key_thread);
INIT_APP_EXPORT(key_int);
任务六:超声波测距
1.新建文件ultr.c,编写代码如下:
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>
#define DBG_TAG "ULTR"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* 超声波模块结构体定义 */
struct ultr{
rt_base_t trigPin; /* RTIG引脚 */
rt_base_t echoPin; /* ECHO引脚 */
uint32_t dis; /* 测量到的距离 */
};
/* 超声波模块实例定义,表示某个超声波模块 */
struct ultr hcsr04={
.echoPin = GET_PIN(B, 1), /* ECHO引脚定义*/
.trigPin = GET_PIN(B, 0), /* RTIG引脚定义*/
};
/*测量线程入口函数,传入的参数为测量的时间间隔,单位是毫秒*/
static void ultr_thread_entry()
{
rt_tick_t t1,t2;//定义变量
/* 把TRIG引脚设置为输出模式 */
rt_pin_mode(hcsr04.trigPin, PIN_MODE_OUTPUT);
/* 初始电平设置为低电平 */
rt_pin_write(hcsr04.trigPin, PIN_LOW);
/* 把ECHO引脚设置为输入模式 */
rt_pin_mode(hcsr04.echoPin, PIN_MODE_INPUT);
while(1){
/* 向TRIG引脚输出触发信号,先写高电平,再写低电平,产生10us脉冲 */
rt_pin_write(hcsr04.trigPin, PIN_HIGH);
rt_hw_us_delay(10);
rt_pin_write(hcsr04.trigPin, PIN_LOW);
/* 等待模块返回测量结果,引脚变为高电平表示有测量结果 */
while(PIN_LOW == rt_pin_read(hcsr04.echoPin)); //一直等待ECHO信号
/* 记录此时的系统时间t1,clk1 ,即ECHO信号的上升沿时间*/
t1 = rt_tick_get();
/* 等待返回的脉冲结束 */
while(PIN_HIGH == rt_pin_read(hcsr04.echoPin));//等待ECHO信号结束
/* 记录此时的系统时间t2,clk2 ,即ECHO信号的下降沿时间*/
t2 = rt_tick_get();
/*计算距离,单位为mm,注意RT_TICK_PER_SECOND默认为1000*/
LOG_D("t1=%d,t2=%d\n",t1,t2);
/*计算时要注意,变量可能发生溢出*/
hcsr04.dis = (t2 - t1)*17;//单位是CM
LOG_D("dist=%d cm",hcsr04.dis);
rt_thread_mdelay(1000);//等待下一次测量
}
}
/* 超声波模块初始化函数,主要设置引脚的模式和初始电平,最后创建测量线程 */
int ultr_thread()
{
rt_thread_t tid = RT_NULL;
tid = rt_thread_create("caosb",
ultr_thread_entry,
RT_NULL,
1024,
20, 10);
if (tid != RT_NULL)
rt_thread_startup(tid);
return 0;
}
INIT_APP_EXPORT(ultr_thread);
任务七: 小车行驶控制(学习BSP配置方法与PWM设备使用)
1.配置BSP,参考教材P165(任务9-1中的任务实施),也可直接微信扫码学习配置方法:

具体配置如下:
(0)双击打开配置软件

(1)使能外部高速时钟

(2)配置系统时钟频率

(3)使能串口1

(4)配置定时器4的第3通道和第4通道为PWM输出。

(5)生成BSP代码

(6)关闭配置软件

(7)使能PWM设备驱动

(8)定义PWM设备相关宏

(9)复motor.c和motor.h文件到工程目录的aplication下,编译,下载,在命令行中输入fwd命令,观察小车是否行驶
任务8:电压监测
(1)配置,请参考教材P177(任务实施)进行配置,也可扫码观看配置过程

(2)代码编写
把adc.c文件复制到工程中的aplication中
(3)编译,下载,观看串口信息
任务9:温度测量
(1)查找DS18B20软件包

(2)修改软件包源代码中的一些错误


(3)修改硬件引脚,以适应小车硬件

(4)编译,下载,测试
任务10:红外遥控
(1)配置,参考教材P249(任务实施),或扫描二维码学习

软件配置如下图:

(2)代码
复制infrare_sample.c文件到aplication目录
(3)编译,下载,使用遥控器测试(注意遥控器要对准小车的红外接收管)


任务11 OLED显示
(1)配置工程
参考教材P197[任务实施]的步骤1.项目建立与配置
(2)添加OLED软件包,保存

(3)复制oled.c oled.h到aplication目录
(4)编译,下载,观察OLED是否显示字符。
