使用嵌入式开发板实现对车位锁控制的流程及程序实现

随着城市化进程的加快,新能源汽车呼之欲出。在笔者所在的城市,力帆和长安等公司都先后推出了可供市民租用的电动汽车。在享受租车所带来的便利的同时,汽车的充电就成了一个难题,在城市道路和停车场安装充电桩成为解决这个问题的一个有效的手段。汽车充电时,需要有一个可用于停靠的车位,并且这个车位只能在汽车充电的时候使用,在其他时间都不能被占用。也就是说,每个充电的车位需要有一个车位锁,当有汽车充电的时候,车位锁打开,否则车位锁关闭。

本文用嵌入式开发板实现了对车位锁开关的控制,可供相关项目的开发人员参考。

一、硬件选型

在嵌入式开发板这块,我们选择了天嵌科技的TQ335X开发板,如下图所示:

在车位锁这块,我们选择了泊享网络的带RS485的车位锁,如下图所示:

二、电路连接

嵌入式开发板通过RS485方式和车位锁相连,RS485的电路原理图如下所示:

如上图所示,电路为TTL转RS485电路,通过跳线SW5接口相应配置,使之与串口2相连。

为了实现485通信功能,板载SW5的跳线选择方式如下图所示:

对于车位锁与开发板的连接,要将车位锁的红色连接线(+)与485的A端相连,将车位锁的黄色连接线(-)与485的B端相连。

三、软件开发环境

由于嵌入式开发板使用的是裁剪版的Linux(ubuntu),因此需要在办公电脑(windows系统)上安装对应的交叉编译环境。

首先,我们要安装Vmware虚拟机,笔者使用的虚拟机版本如下图所示:

接着,我们要将嵌入式系统配备的资料光盘中的裁剪版的Linux(ubuntu)系统安装到虚拟机上,以供编译程序时使用。笔者使用的ubuntu版本如下图所示:

在安装了ubuntu之后,还要将交叉编译器装载到系统中。交叉编译器的安装过程可以参看开发板使用手册,只要按照手册中的步骤(如下图所示)安装就可以了。

四、车位锁协议

我们使用程序通过向车位锁下发指令来控制其开关并获取其状态。车位锁的协议如下图所示:

具体而言,各命令的样例如下:

1.开锁命令:55 ADDR 01 01 CRC AA

接收成功返回 5A ADDR 02 01 01 CRC AA

接收失败返回 5B ADDR 03 01 01 00 CRC AA

2.闭锁命令:55 ADDR 01 02 CRC AA

接收成功返回 5A ADDR 02 02 01 CRC AA

接收失败返回 5B ADDR 03 02 01 00 CRC AA

3.读取锁状态:55 ADDR 01 06 CRC AA

执行成功返回 5A ADDR 02 06 STATUS CRC AA

接收失败返回 5B ADDR 03 06 01 00 CRC AA

注:STATUS 各状态为:00-闭锁状态,01-开锁状态,02-中间状态0~90°,03-中间状态90~180°,88-运动状态,10-当前开锁状态并且检测到上面无车。

五、程序编写

有了开发环境,有了协议,那么接下来我们就可以开始编写程序了。根据我们在第二部分的描述,程序要通过串口来连接RS485电路,因此,程序的大体流程为:初始化串口—>向串口发消息—>接收串口的响应消息—>关闭串口。

完整的C代码(LockCtrl.h和LockCtrl.c)如下所示:

LockCtrl.h代码内容:

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>      //文件控制定义
#include <termios.h>    //终端控制定义
#include <errno.h> 

#define DEVICE "/dev/ttySAC2" 

int init_serial(void);  // 打开串口并初始化设置
int uart_send(int fd, char *data, int datalen);   // 串口发送数据
int uart_recv(int fd, char *data, int datalen);    // 串口接收数据
int OpenLock(void);      // 开车位锁
int CloseLock(void);     // 关车位锁
int GetLockStatus(void); // 获取车位锁 状态

LockCtrl.c代码内容:

#include "LockCtrl.h"

int serial_fd = 0; 

// 打开串口并初始化设置
int init_serial(void)
{
    serial_fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
    if (serial_fd < 0)
    {
        perror("open");
        return -1;
    }
    //串口主要设置结构体termios <termios.h>
    struct termios options; 

    /**1. tcgetattr函数用于获取与终端相关的参数。
      *    参数fd为终端的文件描述符,返回的结果保存在termios结构体中
      */
    tcgetattr(serial_fd, &options); 

    /*2. 修改所获得的参数*/
    options.c_cflag |= (CLOCAL | CREAD);    // 设置控制模式状态,本地连接,接收使能
    options.c_cflag &= ~CSIZE;              // 字符长度,设置数据位之前一定要屏掉这个位
    options.c_cflag &= ~CRTSCTS;            // 无硬件流控
    options.c_cflag |= CS8;                 // 8位数据长度
    options.c_cflag &= ~CSTOPB;             // 1位停止位
    options.c_iflag |= IGNPAR;              // 无奇偶检验位
    options.c_oflag = 0;                    // 输出模式
    options.c_lflag = 0;                    // 不激活终端模式
    cfsetospeed(&options, B9600);           // 设置波特率 

    /**3. 设置新属性,TCSANOW:所有改变立即生效*/
    tcflush(serial_fd, TCIFLUSH);           // 溢出数据可以接收,但不读
    tcsetattr(serial_fd, TCSANOW, &options); 

    return 0;
} 

/**
*串口发送数据
*@fd:串口描述符
*@data:待发送数据
*@datalen:数据长度
*/
int uart_send(int fd, char *data, int datalen)
{
    int len = 0;
    len = write(fd, data, datalen);    // 实际写入的长度 

    printf("uart_send:len=%d,datalen=%d\n", len, datalen); 

    if (len == datalen)      // 发送成功
    {
        return len;
    }
    else
    {
        tcflush(fd, TCOFLUSH);   // TCOFLUSH刷新写入的数据但不传送
        return -1;
    } 

    // return 0;
} 

/**
*串口接收数据
*要求启动后,在pc端发送ascii文件
*/
int uart_recv(int fd, char *data, int datalen)
{
    int len = 0, ret = 0;
    fd_set fs_read;
    struct timeval tv_timeout; 

    FD_ZERO(&fs_read);
    FD_SET(fd, &fs_read);
    tv_timeout.tv_sec = (10*20/115200+2);
    tv_timeout.tv_usec = 0; 

    ret = select(fd+1, &fs_read, NULL, NULL, &tv_timeout);
    printf("ret = %d\n", ret);   //如果返回0,代表在描述符状态改变前已超过timeout时间,错误返回-1 

    if (FD_ISSET(fd, &fs_read))
    {
        len = read(fd, data, datalen);
        printf("len = %d\n", len);
        return len;
    }
    else
    {
        perror("select");
        return -1;
    } 

    // return 0;
} 

/**
*开车位锁
*/
int OpenLock(void)
{
    int  iDataLen      = 0;
    int  iRetVal       = 0;
    char szRcvBuf[20]  = {0};

    unsigned char szOpen[6] = {0x55,0x01,0x01,0x01,0x9A,0xAA};     // 55 01 01 01 9A AA

    iRetVal = init_serial();
    if (iRetVal != 0)
    {
        printf("OpenLock: exec init_serial failed!\n");
        return -1;
    }

    iDataLen = uart_send(serial_fd, szOpen, sizeof(szOpen));
    if (iDataLen == -1)
    {
        printf("OpenLock: exec uart_send failed!\n");
        return -1;
    }

    iDataLen = uart_recv(serial_fd, szRcvBuf, sizeof(szRcvBuf));
    if (iDataLen == -1)
    {
        printf("OpenLock: exec uart_recv failed!\n");
        return -1;
    }

    printf("OpenLock: received len=%d\n", iDataLen); 

    if (szRcvBuf[0] == 0x5A)
    {
        printf("OpenLock: open lock success!\n");
    }
    else if (szRcvBuf[0] == 0x5B)
    {
        printf("OpenLock: open lock failed!\n");
    }
    else
    {
        printf("OpenLock: received data is wrong!\n");
    }

    close(serial_fd); 

    return 0;
}

/**
*关车位锁
*/
int CloseLock(void)
{
    int  iDataLen      = 0;
    int  iRetVal       = 0;
    char szRcvBuf[20]  = {0};

    unsigned char szClose[6] = {0x55,0x01,0x01,0x02,0x78,0xAA};    // 55 01 01 02 78 AA 

    iRetVal = init_serial();
    if (iRetVal != 0)
    {
        printf("CloseLock: exec init_serial failed!\n");
        return -1;
    }

    iDataLen = uart_send(serial_fd, szClose, sizeof(szClose));
    if (iDataLen == -1)
    {
        printf("CloseLock: exec uart_send failed!\n");
        return -1;
    }

    iDataLen = uart_recv(serial_fd, szRcvBuf, sizeof(szRcvBuf));
    if (iDataLen == -1)
    {
        printf("CloseLock: exec uart_recv failed!\n");
        return -1;
    }

    printf("CloseLock: received len=%d\n", iDataLen); 

    if (szRcvBuf[0] == 0x5A)
    {
        printf("CloseLock: close lock success!\n");
    }
    else if (szRcvBuf[0] == 0x5B)
    {
        printf("CloseLock: close lock failed!\n");
    }
    else
    {
        printf("CloseLock: received data is wrong!\n");
    }

    close(serial_fd); 

    return 0;
}

/**
*获取车位锁 状态
*/
int GetLockStatus(void)
{
    int  iDataLen      = 0;
    int  iRetVal       = 0;
    char szRcvBuf[20]  = {0};

    unsigned char szStatus[6] = {0x55,0x01,0x01,0x06,0x19,0xAA};   // 55 01 01 06 19 AA 

    iRetVal = init_serial();
    if (iRetVal != 0)
    {
        printf("GetLockStatus: exec init_serial failed!\n");
        return -1;
    }

    iDataLen = uart_send(serial_fd, szStatus, sizeof(szStatus));
    if (iDataLen == -1)
    {
        printf("GetLockStatus: exec uart_send failed!\n");
        return -1;
    }

    iDataLen = uart_recv(serial_fd, szRcvBuf, sizeof(szRcvBuf));
    if (iDataLen == -1)
    {
        printf("GetLockStatus: exec uart_recv failed!\n");
        return -1;
    }

    printf("GetLockStatus: received len=%d\n", iDataLen); 

    if (szRcvBuf[0] == 0x5A)
    {
        printf("GetLockStatus: get lock status success!\n");

        if (szRcvBuf[4] == 0x00)
        {
            printf("Locked!\n");
        }
        else if (szRcvBuf[4] == 0x01)
        {
            printf("Opened!\n");
        }
        else if (szRcvBuf[4] == 0x02)
        {
            printf("Middle status(0~90)!\n");
        }
        else if (szRcvBuf[4] == 0x03)
        {
            printf("Middle status(90~180)!\n");
        }
        else if (szRcvBuf[4] == 0x88)
        {
            printf("Running status!\n");
        }
        else if (szRcvBuf[4] == 0x10)
        {
            printf("Opened and no car on it!\n");
        }
    }
    else if (szRcvBuf[0] == 0x5B)
    {
        printf("GetLockStatus: Get lock status failed!\n");
    }
    else
    {
        printf("GetLockStatus: GetLockStatus: received data is wrong!\n");
    }

    close(serial_fd); 

    return 0;
}

// 主函数
int main(int argc, char **argv)
{
    int iRetVal = 0;

    // 开锁
    iRetVal = OpenLock();
    if (iRetVal != 0)
    {
        printf("Open lock failed!\n");
        return -1;
    }

    // 闭锁
    sleep(10);
    iRetVal = CloseLock();
    if (iRetVal != 0)
    {
        printf("Close lock failed!\n");
        return -1;
    }

    // 开锁
    sleep(10);
    iRetVal = OpenLock();
    if (iRetVal != 0)
    {
        printf("Open lock failed!\n");
        return -1;
    }

    // 获取车位锁 状态
    sleep(10);
    iRetVal = GetLockStatus();
    if (iRetVal != 0)
    {
        printf("Get lock status failed!\n");
        return -1;
    }

    return 0;
}

六、程序编译及运行

将LockCtrl.c和LockCtrl.h文件拷贝到交叉编译环境上,并使用“arm-linux-gcc -g -o LockCtrl LockCtrl.c”命令编译程序,生成LockCtrl文件。

接着,通过FTP工具或“ftpget -u XXX -p XXX 10.10.10.10 LockCtrl”命令将LockCtrl文件上传到嵌入式开发板的特定目录下,修改权限之后执行“./LockCtrl”命令,可以看到程序正常运行,车位锁成功执行了开关操作。程序的输出如下:

[[email protected] local]# ./LockCtrl
uart_send:len=6,datalen=6
ret = 1
len = 7
OpenLock: received len=7
OpenLock: open lock success!
uart_send:len=6,datalen=6
ret = 1
len = 7
CloseLock: received len=7
CloseLock: close lock success!
uart_send:len=6,datalen=6
ret = 1
len = 7
OpenLock: received len=7
OpenLock: open lock success!
uart_send:len=6,datalen=6
ret = 1
len = 7
GetLockStatus: received len=7
GetLockStatus: get lock status success!
Opened!

七、总结

本文介绍了通过嵌入式开发板控制车位锁开关的流程,并给出了完整的C代码实现。对于嵌入式开发,大家不仅要懂得如何编写程序,还要了解开发板的电路原理及接线方式,这对开发者提出了更高的要求。

时间: 2024-10-29 04:23:26

使用嵌入式开发板实现对车位锁控制的流程及程序实现的相关文章

计算机三级嵌入式开发技术

一单项选择题 1. 世界上第一台计算机研制成功的年代是( C ) Α.1944年 B.1945年 C.1946年 D.1947年 2. 十进制数235,用二进制表达为( A ) Α.11101011 B.11101010 C.11101001 D.11101110 3. ARM采用定长指令格式,所有指令都是32位,Bit[31:28]为( B ) Α.目标寄存器编码 B.条件执行 C.指令操作符编码 D.永远是0 4. 8080处理器是( C ) Α.32位处理器 B.16位处理器 C.8位处理

嵌入式开发需要学习哪些东西

本文转自迅为开发板iTOP-4412开发板实战手册:http://www.topeetboard.com 刚刚读到这篇文章,对于刚入门嵌入式来说挺有用的,献给向我一样正在迷茫,苦于没有头绪,没人指引的学习朋友们.主要讨论下嵌入式技术学习方法,主要是针对嵌入式软件.嵌入式技术是一门边缘科学(又称交叉科学),涉及的内容非常广泛,前几年很多学校,包括一流的大学都在讨论要不要设置这个专业.不是说设置这个专业本身有什么问题,而是因为课程设置不容易安排,如果偏硬件的话那就成了电子工程一类的专业,如果偏软的话

ARM嵌入式开发板推荐

arm嵌入式主板具有低成本.高性能.低功耗的特点,是一个嵌入在设备里面做控制.数据处理使用的CPU板,承担着"大脑"的角色,主要是作为工控主板使用.短短几年,ARM嵌入式的异军突起,日益广阔. ARM嵌入式正在成为带动IT产业新增长点,其主要应用在消费类电子行业和工业控制领域,在中国工业控制领域,与国民生产.通讯.医疗.航天.交通相关的嵌入式应用持续快速增长,同时随着智能设备终端应用市场的快速发展,ARM嵌入式产品不断深入人们的日常生活,并推动终端产品的智能水平不断提升.工业和日常智能

【嵌入式开发】裸机引导操作系统和ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )

[嵌入式开发]ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 ) 一. 内存 简介 1. 两大内存分类 ( 1 ) DRAM 简介 ( 定期刷新 | 速度慢 | 成本低 ) DRAM 简介 : 1.硬件描述 : DRAM 基本由一个个小电容基本原件组成, 电容的两端保留电荷; 2.优缺点描述 : ① 优点 : 成本很低, 很便宜; ② 缺点 : 需要 定期刷新数据, 速度较慢; a.

嵌入式开发板丨ARM开发板 学习必备资料- 迅为电子

摘要: ARM开发板 迅为三星Exynos嵌入式开发平台超强GPS模块 iTOP-Exynos4412开发板采用 Exynos4412的主芯片,具有更高的主频和更丰富外设,配置 2GB 双通道 DDR3的内存及 16GB 存储,具有稳定性强.可靠性高,能适用于对性能和处理能力有更高要求的嵌入式系统应用场合. iTOP-Exynos4412开发板内置有无线 WIFI 模块.Bluetooth.GPS.Camera.3G等模组,支持 HDMI1.4(1080P/60Hz)显示,客户可以直接从开发平台

基于软件开发对嵌入式开发的思考

由于本人专业方向是计算机体系结构方向的,平时做嵌入式方面的实验以及项目较多,这个学期又学习了软件工程的课程,因此想借此机会,总结下在软件工程上面学习到的知识,并看看是否有什么能够借鉴到嵌入式方向的开发上面去. 首先我想总结下,软件开发与嵌入式开发的不同之处.作为软件开发,首先应当从用户或者用户的需求入手,明白用户想让你去实现什么功能,而到了具体的实现,有时却限制的不是那么的死.而至于嵌入式的开发,从需求入手是相同的,但是对于实现的方式,却明显不同于传统的软件开发.对于编程语言,不同的嵌入式开发平

第二章 Android系统与嵌入式开发

第二章 Android系统与嵌入式开发 第二章首先要先了解Android和嵌入式Lnux系统有什么区别和联系,嵌入式Linux系统是在嵌入式设备中运行Linux系统:Android系统是在嵌入式设备中运行Android系统. 其区别就是Android系统和Linux系统的区别.Android系统的底层是Linux的内核,上面跑的是Android的java虚拟机.Android系统的UI做的比Lnux好很多. 首先我们应该先了解一下什么是嵌入式,对于嵌入式来说,它是一种“完全嵌入受控器件内部,为特

与一线Linux嵌入式开发project师的对话

转:与一线Linux嵌入式开发project师的对话 陈project师一直做Linux的嵌入式开发.作为在开发一线的project师.他对非常多问题的看法可能更切合实际需求,于是,通过邮件.就嵌入式开发方面的问题,请他谈了一下自己的看法: 问:关于嵌入式开发.我们准备给同学们解说一些入门知识.从你一线开发经验来说,给我们一些建议: 陈工回答: 对于嵌入式Linux入门,假设有一定基础,可以从驱动開始:假设没有基础.我个人建议还是从应用程序開始.由于从应用程序開始是最easy的,也是 最直观的.

转:Qt 嵌入式开发环境搭建

地址: http://www.cnblogs.com/lishixian/articles/3013897.html         作者:lsx_007 这里主要是记录了自己在搭建嵌入式开发环境时阅读的一些有价值的参考文档,文档主要来自于网络,由于是从文库中下载,所以也不知道 文档的出在哪?因为个人觉得总结的比较好,我暂且拿过来记录下,当然在此基础上也会加上我自己的理解!这篇文章主要是以问答的形式来组织. QT嵌入式开发环境是本文所要介绍的内容,我们先看看Qt的各个版本简介: 1.什么是QT