linux 小项目开发-1-概括和start(linux-SPI驱动小结)

2023-05-16

 

项目的要求:环境温度的检测和报警系统
系统介绍:
实时读取环境温度、读/写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.串口驱动

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux 小项目开发-1-概括和start(linux-SPI驱动小结) 的相关文章

随机推荐