基于I.MX6ULL + LINUX驱动程序 Qt车载系统
Qt车载系统都是基本功和API调用,硬件也涉及的少,交叉编译的话WEB模块是编译不过去的,当时我问了正点原子官方他们原话:(6ull不支持webengewidgets。就算你能交叉编译出来,6ull估计跑不动。6ull上有webview。webengine编译相关源码500MB。mp157和rk3568上有webengine,如果你有这两板子)还有一个bug板子上Qt程序对两个驱动文件读数据时会直
Qt车载系统有的功能:音视频播放、天气显示、地图显示、起点搜索和终点搜索,路线导航,倒车影像,倒车障碍实时距离显示,温湿度曲线绘制,交叉编译,程序优美界面。
使用技术: Qt应用程序开发,Linux 驱动程序开发,HC-SR04超声波模块驱动,Linux C嵌入式应用,JavaScript,Qt WebEngine(内嵌HTML),HTTP,JSON。
基于I.MX6ULL + LINUX驱动程序 Qt车载系统
HC-SR04超声波模块驱动:
使用新字符设备驱动开发框架 (配置寄存器方式) 编写好HC-SR04超声波模块驱动 ,并提供应用层控制接口,然后将 .ko 文件拷入开发板加载入内核。每次应用空间对驱动文件读操作,将返回超声波模块一次声波来回的间隔时间(纳秒),根据公式将此数据转换为秒,然后带入L=V * T / 2,得出倒车距离。 这里用让驱动层返回纳秒的而不是距离的原因是:Linxu内核对浮点数操作挺麻烦的就直接传给应用层让QT去搞简简单单。
驱动源码:初始化两个GPIO引脚
#ifndef _MAIN_
#define _MAIN_
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/ktime.h>
#include<linux/types.h>
/* 寄存器物理地址 */
#define CCM_CGPR1_BASE (0x020C406C) //GPIO1
#define MUX_CTL_PAD_GPIO1_IO04_BASE (0x020E006C)
#define MUX_CTL_PAD_GPIO1_IO09_BASE (0x020E0080)
#define PAD_CTL_PAD_GPIO1_IO04_BASE (0x020E02F8)
#define PAD_CTL_PAD_GPIO1_IO09_BASE (0x020E030C)
#define GPIO1_DR_BASE (0x0209C000)
#define GPIO1_GDIR_BASE (0x0209C004)
/* 映射后的寄存器虚拟地址指针 */
static void __iomem * CCM_CGPR1;
static void __iomem *MUX_CTL_PAD_GPIO1_IO04;
static void __iomem *MUX_CTL_PAD_GPIO1_IO09;
static void __iomem *PAD_CTL_PAD_GPIO1_IO04;
static void __iomem *PAD_CTL_PAD_GPIO1_IO09;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;
void register_init(void);
void HC_SR04_Init(void);
void myexit(void);
unsigned long long Test_Distance(void);
void SetBits(void); //25
void ResetBits(void);
unsigned int ReadInputDataBit(void); //24
void register_init(void)
{
printk("register_init\r\n");
CCM_CGPR1=ioremap(CCM_CGPR1_BASE,4);
MUX_CTL_PAD_GPIO1_IO04=ioremap(MUX_CTL_PAD_GPIO1_IO04_BASE, 4);
MUX_CTL_PAD_GPIO1_IO09=ioremap(MUX_CTL_PAD_GPIO1_IO09_BASE,4);
PAD_CTL_PAD_GPIO1_IO04=ioremap(PAD_CTL_PAD_GPIO1_IO04_BASE,4);
PAD_CTL_PAD_GPIO1_IO09=ioremap(PAD_CTL_PAD_GPIO1_IO09_BASE,4);
GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
}
unsigned long long Test_Distance(void)
{
unsigned long long start_time, end_time, diff_time;
SetBits(); //25
udelay(30);
ResetBits(); //25
//read 24
while(ReadInputDataBit()==0);
start_time = ktime_get_ns();
while(ReadInputDataBit()==1);
end_time = ktime_get_ns();
diff_time = end_time - start_time;
mdelay(100);
return diff_time;
}
void HC_SR04_Init(void)
{
unsigned int val;
/*开启GPIO1时钟*/
val = readl(CCM_CGPR1);
val &= ~(3 << 26); /* 清除以前的设置 */
val |= (3 << 26); /* 设置新值 */
writel(val, CCM_CGPR1);
/*将引脚复用为GPIO1_IO1 2*/
writel(5, MUX_CTL_PAD_GPIO1_IO04); //4
writel(5, MUX_CTL_PAD_GPIO1_IO09); //9
//设置电气属性
writel(0xF080, PAD_CTL_PAD_GPIO1_IO04); //4输入模式
writel(0x10B0, PAD_CTL_PAD_GPIO1_IO09); //9输出模式
/* 4、设置GPIO1_IO4为输入功能 */
val = readl(GPIO1_GDIR);
val &= ~(1 << 4); /* 输入*/
writel(val, GPIO1_GDIR);
/* 4、设置GPIO1_IO9为输出功能 */
val = readl(GPIO1_GDIR);
val |= (1 << 9); /* 输出*/
writel(val, GPIO1_GDIR);
}
void SetBits(void) //9
{
u32 val;
val = readl(GPIO1_DR);
val |= (1 << 9); /*9*/
writel(val, GPIO1_DR);
}
void ResetBits(void)
{
u32 val;
val = readl(GPIO1_DR);
val &= ~(1 <<9); /* 9*/
writel(val, GPIO1_DR);
}
unsigned int ReadInputDataBit(void) //4
{
u32 val;
val=readl(GPIO1_DR);
return (((val) >> 4) & 0x1);
}
void myexit(void)
{
iounmap(CCM_CGPR1);
//.......
}
#endif // !_MAIN_
Qt计算距离
int fd= open("/dev/newchriobee",O_RDWR);//打开文件
if(fd<0)
return;
read(fd,buffer,sizeof(buffer));
if(buffer[0]=='\0')return;
QString str=buffer; //时间 str 纳
float re_ms=str.toDouble()/1000000000; //得到秒
float distance=(re_ms*340)/2; //距离公式
ui->label->setText("倒车障碍距离:"+QString::number(distance,'f',2));
地图显示、起点搜索和终点搜索,路线导航:
这个需要用到模块 Qt WebEngine;基于Qt与JavaScript的交互更新HTML。高德地图官网有web API接口,直接复制JS的案例,就可以创建出地图对象显示在HTML上,Qt用 Qt WebEngine 显示本地网页内嵌HTML,Qt然后创建HTML对象,定义需要暴露的槽函数和信号,设置channel对象,这样HTML客户端就可以通过channel.objects属性访问所有已发布的对象,完成交互。JS给Qt的数据都JSON格式,需要解析,然后根据数据发送信号给主窗口来更改ui界面
<script>
//高德地图API,创建map对象,创建出来就有了地图
var map = new AMap.Map('container', {
viewMode: '2D', // 默认使用 2D 模式,如果希望使用带有俯仰角的 3D 模式,请设置 viewMode: '3D'
zoom: 11, // 初始化地图层级
});
//加载这个地图的自动补全插件
AMap.plugin(["AMap.Autocomplete"], function () {
});
//QT与HTML交互
var mchannel;
window.onload = function () {
if (typeof qt != 'undefined') {
new QWebChannel(qt.webChannelTransport, function (channel) {
// 与QT MyChannel的信号绑定
channel.objects.qtChannel.qiDianChanged.connect(_qiDianChanged); //qiDianChanged是QT的信号,然后绑定_qiDianChanged函数
channel.objects.qtChannel.destChanged.connect(_destChanged);
channel.objects.qtChannel.sendQiLocation.connect(setQiLocation);
channel.objects.qtChannel.sendDestLocation.connect(setDestLocation);
channel.objects.qtChannel.selectRoute.connect(setRoute);
mchannel = channel;
});
}
else {
alert("qt对象获取失败!");
}
}
var autoComplete = new AMap.Autocomplete({});
//QT的起点搜索栏 内容变化时就会触发该信号,然后再调用高德地图的api搜索,然后把搜索的内容发送给QT
function _qiDianChanged(pos) {
autoComplete.search(pos, function (status, result) {
// 搜索成功时,result即是对应的匹配数据
mchannel.objects.qtChannel.qiAutocomplete(result);
});
}
//QT的终点搜索栏 内容变化时就会触发该信号,然后再调用高德地图的api搜索,然后把搜索的内容发送给QT
function _destChanged(pos) {
autoComplete.search(pos, function (status, result) {
// 搜索成功时,result即是对应的匹配数据
mchannel.objects.qtChannel.destAutocomplete(result);
});
}
var startIcon = new AMap.Icon({
// 图标尺寸
size: new AMap.Size(25, 34),
// 图标的取图地址
image: 'http://a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
// 图标所用图片大小
imageSize: new AMap.Size(135, 40),
// 图标取图偏移量
imageOffset: new AMap.Pixel(-9, -3)
});
var startMarker;
var startLocation;
//QT中QListView选中地点后,会发送信号,并把位置信息带上,然后这里调用高德地图API设置起点的标志,并把坐标放在startLocation
function setQiLocation(location) {
if (startMarker != null) {
map.remove(startMarker);
}
var pos = location.split(",");
startLocation = pos;
map.setCenter(pos);
startMarker = new AMap.Marker({
position: pos,
icon: startIcon,
offset: new AMap.Pixel(-13, -30)
});
map.add(startMarker);
}
// 创建一个 icon
var endIcon = new AMap.Icon({
size: new AMap.Size(25, 34),
image: 'http://a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
imageSize: new AMap.Size(135, 40),
imageOffset: new AMap.Pixel(-95, -3)
});
var endMarker;
var endLocation;
//QT中QListView选中地点后,会发送信号,并把位置信息带上,然后这里调用高德地图API设置终点的标志,并把坐标放在endLocation
function setDestLocation(location) {
if (endMarker != null) {
map.remove(endMarker);
}
var pos = location.split(",");
endLocation = pos;
map.setCenter(pos);
endMarker = new AMap.Marker({
position: pos,
icon: endIcon,
offset: new AMap.Pixel(-13, -30)
});
map.add(endMarker);
}
var driving = new AMap.Driving({
map: map,
panel: "panel"
});
// 点击导航按钮后,发送信号,然后这里判断endLocation和startLocation是否为NULL,不为空就说明设置了起点,然后调用高德地图API进行导航
function setRoute() {
if (endLocation != null && startLocation != null) {
driving.search(startLocation, endLocation, function (status, result) {
if (status === 'complete') {
log.success('绘制驾车路线完成')
map.setCenter(startLocation)
} else {
log.error('获取驾车数据失败:' + result)
}
});
}
else {
alert("请输入起点和终点");
}
}
</script>
天气显示
天气显示通过HTTP协议访问API接口,得到一个JSON字符串,然后将其解析。API接口 http://t.weather.itboy.net/api/weather/city/+城市编号
音视频播放
通过QMediaPlayer,QMediaPlaylist 创建媒体对象和媒体列表,媒体列表会自动扫描当前目录下的music文件夹自动更新,切换上一首,下一首功能根据媒体列表对象来实现,播放模式,进度条扫描的都i有相对于API。视频的话和上面基本一样,需要设置一个播放视频的容器QVideoWidget
温湿度曲线绘制
正点原子官方已经写好了DTH11的驱动程序,我们直接加载到内核,用Qt定时器定时去读该文件获取温湿度数据,然后绘制就好了。
总结:
Qt车载系统都是基本功和API调用,硬件也涉及的少,交叉编译的话WEB模块是编译不过去的,当时我问了正点原子官方 他们原话:(6ull不支持webengewidgets。就算你能交叉编译出来,6ull估计跑不动。6ull上有webview。webengine编译相关源码500MB。mp157和rk3568上有webengine,如果你有这两板子)
还有一个bug 板子上Qt程序对两个驱动文件读数据时会直接卡死了,我查了好久资料都查不到原因,不管了都无所谓,能跑就行。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)