01开发板上LED灯和蜂鸣器的控制
蜂鸣器:
在Linux中,蜂鸣器同样是一个文件(Linux系统把它抽象成一个文件)我们系统中的蜂鸣器驱动是使用ioctl控制的,我们需要替换驱动(安装新的蜂鸣器驱动)
原先的驱动是嵌入到系统中,每一次重启都会默认安装原先的驱动
步骤:
1. 先上传蜂鸣器驱动
rx pwm.ko2. 安装驱动(每一次重启都需要重新安装,可以写入配置文件)
insmod pwm.ko
insmod: can't insert 'pwm.ko': Device or resource busy
===============>
系统中固定的驱动一直占用这个设备,需要把原始的驱动卸载
rmmod gec6818_beep.ko卸载之后,重新安装
成功之后,会在/dev/目录下面生成一个对应的设备结点,代表蜂鸣器这个设备,名称"/dev/pwm"3. 操作蜂鸣器
1) 打开蜂鸣器文件
2) 写入控制数据(由驱动决定)
3) 关闭设备LED灯:
在Linux中,LED同样是一个文件(Linux系统把它抽象成一个文件)
1. 先上传LED驱动
rx led_drv.ko2. 安装驱动(每一次重启都需要重新安装,可以写入配置文件)
insmod led_drv.ko
成功之后,会在/dev/目录下面生成一个对应的设备结点,代表蜂鸣器这个设备,名称"/dev/led_drv"3. 操作LED
1) 打开LED文件
2) 写入控制数据(由驱动决定)
3) 关闭设备
02C语言中多线程接口
C语言中默认情况下,只有一个执行流程,但是在开发的过程中,可能需要程序能够同时执行多个任务(拥有多条执行分支)
=======>
并发(多进程/多线程)多线程的API函数接口(可以创建一条分支,让程序执行指定的任务)
NAME pthread_create - create a new thread 创建一个新的线程 SYNOPSIS #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); thread:指针,指向一块可用的内存空间,用来保存新创建的线程的线程号码 attr:指定新创建的线程的线程属性,一般为NULL,表示使用默认属性 start_routine:是一个函数指针,指定了线程需要完成的任务,新创建的线程就会去执行这个函数 arg:线程函数的参数 返回值: 成功返回0,失败返回-1; Compile and link with -pthread.
03串口编程和传感器的使用
串口是一种非常重要的通信协议(用到的地方非常多),特点是一个bit一个bit的传输数据
波特率:1s能够传输的bit的数量(传输速度)开发板的右上角由4组外接串口(COM2/COM3/COM4/COM5),可以连接其他支持串口的任何设备,其中:COM2/COM3/COM4可以正常使用,COM5虽然有硬件,但是没有驱动,不能使用。
串口有4根线
VCC 电源
GND 接地
TX transfer 发送端
RX recive 接收端串口通信是两个设备之间的通信,两个设备都有4个接口,接线的方式是交叉接线
设备A 设备B
VCC -------- VCC
GND -------- GND
TX -------- RX
RX -------- TX注意:
1.断电接线(传感器容易损坏)
2.接线的时候以PCB底板的标识为准
3.如果收不到数据
a.线是否接对了(TX/RX,或者没有接到指定的串口)
b.传感器是否本身就是坏的
c.代码问题串口编程的步骤:
串口在Linux中也是文件
1.初始化串口(设置串口的通信属性)
a.打开串口设备对应的文件名
文件名:
COM1------>"/dev/ttySAC0" 通信串口,和电脑相连的那个接口
COM2------>"/dev/ttySAC1"
COM3------>"/dev/ttySAC2"
COM4------>"/dev/ttySAC3"
b.设置串口的属性
波特率
数据位
停止位
....
2.读写数据(需要按照传感器设备的通信协议收发数据)
发送: write 发送指令给传感器
接收: read 从传感器读取数据
3.关闭串口
close(...)按照传感器设备的通信协议收发数据:
超声波:
波特率:9600
输出的距离值共两个字节,第一个字节是距离的高 8 位(HDate),第二个字节距离的低 8 位(LData),单位为毫米。即距离值为 (HData*256 +LData)mm。
HData << 8 | LData烟雾传感器的通信协议:
波特率:9600
发送的命令是9字节
0xFF,0x01,0x86,0x0,0x0,0x0,0x0,0x0,0x79
接收9个字节:
其中第三个字节和第四个字节表示得到的可燃气体浓度
GY39的通信协议:
默认波特率值 9600bps
模块输出格式,每帧包含9或者15个字节
①.Byte0: 0x5A 帧头标志
②.Byte1: 0x5A 帧头标志
③.Byte2: 0x15/0x45 本帧数据类型
0x15 这一帧数据包含光照强度
0x45 这一帧数据包含温度、气压、湿度、海拔数据的计算方法:
当Byte2=0x15时,数据表示的是光照强度,保存在,Byte4~Byte7) :
Lux=(前高8位<<24) | (前低8位<<16) | (后高8位<<8) | 后低8位 单位lux
例:一帧数据
<5A- 5A- 15 -04- 00 -00- FE- 40- 0B >
Lux=(0x00<<24)|(0x00<<16)|(0xFE<<8)|0x40
Lux=Lux/100 =650.88 (lux)
当Byte2=0x45时,数据表示的是温度、气压、湿度、海拔
温度保存在 Byte4~Byte5
T=(高 8 位<<8)|低 8 位
T=T/100 单位℃
气压保存在 Byte6~Byte9
P=(前高 8 位<<24) | (前低 8 位<<16) | (后高 8 位<<8) | 后低 8 位
P=P/100 单位 pa
湿度保存在 Byte10~Byte11
Hum=(高 8 位<<8)|低 8 位
Hum=Hum/100 百分制
海拔保存在Byte12~Byte13
H=(高 8 位<<8)|低 8 位 单位 m
例:一帧数据
< 5A -5A -45 -0A -0B -2D -00 -97 -C4 -3F -12- 77 -00- 9C- FA >
T=(0x0B<<8)|0x2D=2861
温度 T=2861/100=28.61 (℃)
P=(0x00<<24)|(0x97<<16)|(C4<<8)|3F=9946175
气压 P=9946175/100=99461.75 (pa)
Hum=(0x12<<8)| 77=4727
湿度 Hum=4727/100=47.27 (%)
海拔 H=(0x00<<8)|0x9c=156 (m)
============================================================
需要发送的命令:
GY-39是一个配置型的传感器,只需要向它发送一次命令,就会不断的返回数据
发送的命令(由外部控制器发送至GY39)
所有串口指令格式:帧头(0xA5)+指令+校验和(8bit)
帧头:固定是0xA5
指令:
连续输出温度,气压,湿度,海波 0x82
连续输出光照强度 0x81
校验和:
0xA5 + 0x82 =======> 0x27
0xA5 1010 0101
0x82 1000 0010
-------------------------
0010 0111 -----》0x27
0xA5 + 0x81 =======> 0x26发送命令:
0xA5+0x81+0x26,表示连续输出光照强度
回复9个字节,光照强度保存到第4个位到第7个位
5a 5a 15 4 0 0 15 cc ae0xA5+0x82+0x27,表示连续输出温度,气压,湿度,海波
回复15个字节......
5a 5a 45 a d 68 0 98 23 94 17 c 0 87 71
0xA5+0x83+0x28 表示连续输出光照强度以及温度,气压,湿度,海波
回复9+15个字节为一帧数据
5a 5a 15 4 0 0 15 cc ae 5a 5a 45 a 9 d4 0 98 1f e 17 f1 0 88 35
void monitor_temp()
{
//初始化串口
int fd = init_serial("/dev/ttySAC3",9600);
if(fd == -1)
{
printf("初始化串口失败!");
return;
}
//按照通信协议收发数据
//char cmd[3] = {0xA5,0x81,0x26};//光照强度
//char cmd[3] = {0xA5,0x82,0x27};//温湿度强度
char cmd[3] = {0xA5,0x83,0x28};//光照强度 + 温湿度强度
//是配置型传感器,只需要发送一次命令即可
write(fd,cmd,3);
sleep(1);
//不断的读取数据
while(1)
{
sleep(1);
char ack[32] = {0};
int r = read(fd,ack,32);
if(r != 9 && r!=15 && r!= 24) //光照强度会返回9个字节,温湿度会返回15个字节
{
printf("GY39-read data error:%d\n",r);
continue;
}
//验证数据的正确性
int i;
for(i=0;i<r;i++)
{
printf("%x ",ack[i]); //原始数据
}
printf("\n");
/*
if(ack[0] == 0x5a && ack[1] == 0x5a) //验证数据的正确性
{
int lux = ack[4] << 24 | ack[5] << 16 | ack[6] << 8 | ack[7];
lux = lux/100;
printf("lux_value = %d\n",lux);
}
*/
/*
if(ack[0] == 0x5a && ack[1] == 0x5a) //验证数据的正确性
{
int temp = ack[4] << 8 | ack[5];
temp = temp/100;
printf("temp_value = %d\n",temp);
}
*/
}
//关闭串口
close(fd);
}