项目的要求:环境温度的检测和报警系统
系统介绍:
实时读取环境温度、读/写IIC接口的EEPROM、控制管显示、按键编程、串口/网口输出数据、LED显示闪烁报警、蜂鸣器响声告警,本地GUI显示状态(显示系统时间,本地天气和系统状态等)--因此构成一套简单的环境温度检测和报警系统;
应用分配:
(1) 使用 EEPROM 保存用户设置的最低安全温度和最高安全温度;
(2) 在数码管切换显示最低安全温度、最高安全温度以及当前温度;
(3) 通过按键设置最安全低温度和最高安全温度,并保存在 EEPROM;
(4) 当环境温度不在安全温度范围之内时,发出声/光警报(声音-蜂鸣器,光-led快闪);
(5)用串口通讯或网口tcp/ip通讯向外部传输当前的系统数据
(6)QT-GUI显示本机的状态
系统拓扑图:
-----------------------------------测试驱动----------------------------------------------------
1.数码管显示-SPI驱动
(1)stm32的spi驱动初始化,主要配置两个要点:1-是总线时钟+总线的配置,2-是GPIO时钟+GPIO的管教配置,如下图
(2)linux的驱动初始化也是如此两个要点,1-确认硬件连接--要可开启设备(SPI 总线设备文件和 GPIO 属性文件),2-配置号spi总线的通讯配置(即设置 SPI 总线参数:总线极性、总线的最大频率、数据字的大小)
伪代码如下:
int main(int argc, char *argv[])
{
int ret = 0;
int fd_spi = 0;
int fd_gpio = 0;
int led_value = 0;
int led_num = 0;
fd_spi = open(SPI_DEVICE, O_RDWR);
fd_gpio = open(GPIO_DEVICE, O_RDWR);
ret = ioctl(fd_spi, SPI_IOC_WR_MODE, &mode); /* set spi mode */
ret = ioctl(fd_spi, SPI_IOC_WR_BITS_PER_WORD, &bits); /* set spi bits per word */
ret = ioctl(fd_spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed); /* max speed hz */
show_led_num(fd_spi, fd_gpio, led_value, led_num);
close(fd_spi);
return ret;
}
总线极性:关于SPI的总线参数--极性和时序说明
总线的最大频率:SPI 总线的最大速率设置后,在使用过程并不是只能使用该频率收/发数据,而仅仅约束收/发数据时的最大频率
数据字的大小:设置 SPI 总线上每字的数据位长度
2.eeprom的掉电存储应用-iic驱动开发
stm32的初始化操作也是类似,主要两个要点:1-是总线时钟+总线的配置(地址、时钟等),2-是GPIO时钟+GPIO的管脚配置
linux的初始化也是如此(更简单),1是打开对应的硬件地址,2是配置设备(从机地址和设置地址长度);
伪代码对比如下(左为stm32的iic初始化配置,右为linux-iic驱动测试伪代码):
时序:(单字节读/写 和多字节读/写,单字节每次都有写地址,多字节--连续读/写多个字节--不需多次写地址)
3.ADC-温度检测
ADC的驱动有两种,一种是 LRADC 对应的驱动(一种 Low-ResolutionADC-LRADC 低分辨率--比如温度/电压采集!)。另一种为 HSADC对应的驱动(High-SpeedADC-HSADC高速ADC,每秒可达 2MSPS--高速 ADC,可用于摄像头数据采集);
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
#include <sys/ioctl.h>
#include "lradc.h"
#define LRADC_DEV "/dev/magic-adc" /* adc 设备文件名 */
#define CMD_VOLTAGE IMX28_ADC_CH0 /* 通道 0 读取命令 */
#define CMD_TEMPTURE IMX28_ADC_CH1 /* 通道 1 通读读取命令 */
#define R33 2000
#define V_ADC 3.3
#define T1 (273.15 + 25)
#define R1 27600
#define B 3435*1000
int main(int argc,char **argv)
{
short buff[100];
int i, fd, value_R, value_T, cmd, ret, len = 2;
float voltage, RT, temp,resistance;
fd = open (LRADC_DEV,O_RDONLY); /* 打开ADC设备 */
if (fd < 0) {
perror("open");
close(fd);
return 0;
}
ret = ioctl(fd, CMD_VOLTAGE, &value_R); /* 读取通道 0 */
if(ret != 0){
perror("ioctl");
return -1;
}
ret = ioctl(fd, CMD_TEMPTURE, &value_T); /* 读取通道 1 */
close(fd);
if(ret != 0) {
perror("ioctl");
return -1;
}
resistance = (value_R*1.85)/4096.0; /* 计算通道 0 测量电压 */
voltage = (value_T*1.85)/4096.0; /* 计算通道 1 测量电压 */
RT = (V_ADC/voltage - 1)*R33; /* 计算热敏电阻的阻值 */
temp = 3435/log(10*RT) - 273.15; /* 计算热敏电阻的温度 */
printf("A10 电阻电压 %fV ;A11 加热电阻温度 %f\n",resistance, temp);
return 0;
}
4.键盘检测
key.ko驱动模块加载完成( rmmod key.ko)后,将在/dev/input 目录生成设备文件/dev/input/event1(无usb鼠标和usb键盘)
键盘事件的结构体:
struct input_event {
struct timeval time;//有A和B两个long成员-可表示A.B秒(如a=1,B=123,表示时间启动1.123000s)
__u16 type;//事件类型,0-事件提交,1-按键事件,2-相对坐标事件(鼠标),3-绝对坐标事件(触摸屏)
__u16 code;//码值-与硬件相关,比如某键盘上的字母A-码值为30,B-48..
__s32 value;//value成员对于不同的输入事件有不同的意义。eg.按键事件,value可取值为:1(表示键按下)和 0(表示键提起)
}
测试代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>//加载key*.ko驱动后,会有event0/1/2..时间在input下
int main (int argc, char * argv[])
{
int fd,count;
struct input_event input_event_value;//input_event为input下的结构体
char input_type[20];
if (argc !=2 ) {//判断程序是否有输入参数,如果没有程序退出
printf("usage : input_type /dev/input/eventX\n");
return 0;
}
fd = open (argv[1], O_RDWR);
if (fd < 0) {//打开输入设备,设备的名称为程序的输入参数提供
printf ("open %s failed\n", argv[1]);
exit(0);
}
while(1) {//循环读取输入事件,然后打印事件信息的结构体
count=read(fd, &input_event_value, sizeof(struct input_event));
if (count < 0) {
printf("read iput device event error \n");
return -1;
}
switch(input_event_value.type) {//判断事件的类型
case EV_SYN:
strcpy(input_type, "SYNC");
break;
case EV_REL:
strcpy(input_type, "REL");
break;
case EV_ABS:
strcpy(input_type, "ABS");
break;
case EV_KEY:
strcpy(input_type, "KEY");
break;
default:
printf("even type unkown \n");
return -1;
}
printf("time:%ld.%ld",input_event_value.time.tv_sec,input_event_value.time.tv_usec);
printf(" type:%s code:%d value:%d\n",input_type,input_event_value.code,input_event_value.value);
}
return 0;
}
5.GPIO操作-LED/蜂鸣器开发
6.tcp/ip网络通讯
7.串口驱动