信息采集与监测系统项目:开发板服务器以及驱动部分

#include "head.h"
char buf[1024];
int num;
pthread_t pth; // 读取温湿度线程pth

//信号捕获Ctrl+c卸载驱动
void handler(int signum)
{
	//对传入的信号号进行判断
	if(signum == SIGINT)
	{
		close(fd_t);//关闭si7006目录对应的文件描述符
		close(fd1_t);//关闭m74hc595
		system("rmmod spi.ko");
		system("rmmod gpiod_led.ko");
		system("rmmod pwm.ko");
		system("rmmod temp_hum_i2c.ko");
		system("rmmod fan.ko");
	}
	exit(0);//退出程序
	return;
}
int main(int argc, const char *argv[])
{

	//捕获信号,处理自定义逻辑
	if( signal(SIGINT, handler) == SIG_ERR )
	{
		perror("signal error");
		return -1;
	}
	//装驱动
	system("insmod spi.ko");
	system("insmod gpiod_led.ko");
	system("insmod pwm.ko");
	system("insmod temp_hum_i2c.ko");
	system("insmod fan.ko");
	int sfd= socket(AF_INET, SOCK_STREAM, 0);
	// 1.创建套接字
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket is success\n");
	// 2.允许端口快速复用
	int reuse = 1;
	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	printf("setsockopt is success\n");
	// 3.链接服务器
	struct sockaddr_in addr; // 填充服务器属性
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);		  // 端口
	addr.sin_addr.s_addr = inet_addr(IP); // ip

	// 绑定工作
	if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind is success\n");

	// 将套接字转换成被动监听状态
	if (listen(sfd, 128) < 0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");

	struct sockaddr_in cin; // 存储客户端的地址信息
	socklen_t addrlen = sizeof(cin);

	// 获取连接成功的客户端信息,生成一个新的文件描述符,
	// 该文件描述符才是与客户端通信的文件描述符
	// int newfd = accept(sfd, NULL, NULL);
	newfd = accept(sfd, (struct sockaddr *)&cin, &addrlen);
	if (newfd < 0)
	{
		ERR_MSG("accept");
		return -1;
	}
	printf("[%s:%d] newfd=%d 客户端连接成功__%d__\n",
		   inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, __LINE__);

	char buf[1024] = "";
	char chum[128] = "";
	char ctemp[128] = "";

	ssize_t res = 0;

	// 功能分区
	while (1)
	{
	//接收数据
		bzero(buf, sizeof(buf));
        res = recv(newfd, buf, sizeof(buf), 0);
        //res = read(newfd, buf, sizeof(buf));
        if(res < 0)
        {
            ERR_MSG("recv");
            return -1;
        }
        else if(0 == res)
        {
            printf("[%s:%d] newfd=%d 客户端下线__%d__\n", \
                    inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, __LINE__);
			close(fd_t);//关闭si7006目录对应的文件描述符
			close(fd1_t);//关闭m74hc595
			system("rmmod spi.ko");
			system("rmmod gpiod_led.ko");
			system("rmmod pwm.ko");
			system("rmmod temp_hum_i2c.ko");

            break;
        }

        printf("[%s:%d] newfd=%d : %s __%d__\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, buf, __LINE__);

        if(strcmp(buf, "quit") == 0)
            break;    

		cJSON* json = cJSON_Parse(buf);
		//cJSON* item =NULL;
		//char *json_data = NULL;
   		printf("data:%s\n",cJSON_Print(json));
		if(!json||!json->child)
		{
			continue;
		}
		num = json->child->valueint;
		// 以空格为分割读取数据 灯0是关1是开
		if(!strcmp(json->child->string,"LED"))//灯1
		{
			printf("LED1\n");
			set_LED_fun(num);
		}
		if(!strcmp(json->child->string,"LED1"))//灯1
		{
			printf("LED1\n");
			set_LED1_fun(num);
		}
		if(!strcmp(json->child->string,"LED2"))//灯2
		{
			set_LED2_fun(num);
		}
		if(!strcmp(json->child->string,"LED3"))//灯3
		{
			printf("LED3\n");
			set_LED3_fun(num);
		}
		//蜂鸣器0是关 100是开
		if(!strcmp(json->child->string,"beep"))//蜂鸣器
		{
			printf("beep\n");
			set_Feng_fun(num);
		}
		if(!strcmp(json->child->string,"fan"))//风扇
		{
			printf("fan\n");
			set_Wind_fun(num);
		}
		if(!strcmp(json->child->string,"warn"))//温湿度低
		{
			set_Feng_fun(100);
			set_Wind_fun(300);
		}
		if(!strcmp(json->child->string,"warn1"))//光照低
		{
			set_LED_fun(1);
			set_Feng_fun(100);
		}

		
		if(!strcmp(json->child->string,"hum"))//温湿度
		{

			if (pthread_create(&pth, NULL, (void *)temp_hum, NULL) < 0)
				{
					ERR_MSG("pthread_create");
					return -1;
				}
				printf("线程创建成功\n");
				// 分离线程交由系统回收
				pthread_detach(pth);
		}
	}
	close(sfd); // 关闭套接字
	close(newfd);
	return 0;
}

👆开发板服务器代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "fan.h"
#define CNAME "fan"
unsigned int major = 0;        // 分配的主设备号
unsigned int *rcc_virt = NULL; // rcc寄存器虚拟地址
gpio_t *gpioe_virt = NULL;     // gpioe组寄存器虚拟地址
unsigned int *rcc_tim1 = NULL; // TIM1使能虚拟地址
tim1_t *tim1_virt = NULL;
struct class *cls = NULL;
struct device *dev = NULL;

long fan_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    // 主要输出使能
    tim1_virt->BDTR |= (0x1 << 15);
    // 设置比较寄存器的使能
    tim1_virt->CCMR1 |= (0x1 << 3);
    // 设置管脚输出使能
    tim1_virt->CCER |= 0x1;
    // 设置计数器使能
    tim1_virt->CR1 |= 0x1;

    tim1_virt->PSC = 209 - 1; // 设置分频器
    tim1_virt->ARR = 10000;   // 设置自动装载器内的数值

    switch (cmd)
    {
    case ONE_FAN:        
        tim1_virt->CCR1 = 8000;   // 设置比较寄存器内的值
        break;
    case TWO_FAN:

        tim1_virt->CCR1 = 5000;     // 设置比较寄存器内的值
        break;
    case THREE_FAN:

        tim1_virt->CCR1 = 1000;   // 设置比较寄存器内的值
        break;
    case CLOSE_FAN:
        tim1_virt->BDTR &= (~(0x1) << 15); // 主要输出使能
        tim1_virt->CCMR1 &= (~(0x1) << 3); // 设置比较寄存器的使能
        tim1_virt->CCER &= ~(0x1);         // 设置管脚输出使能
        tim1_virt->CR1 &= ~(0x1);          // 设置计数器使能
        break;
    }
    return 0;
}

// 操作方法结构体
const struct file_operations fops = {
    .unlocked_ioctl = fan_ioctl,
};

static int __init fan_init(void)
{
    // 注册字符设备驱动
    major = register_chrdev(0, CNAME, &fops);
    if (major <= 0)
    {
        printk("register chrdev is error\n");
        return -EIO;
    }

    // rcc寄存器地址映射
    rcc_virt = ioremap(RCC_PHY_ADDR, 4);
    if (rcc_virt == NULL)
    {
        printk("rcc ioremap is error\n");
        return -EIO;
    }
    // GPIOE组寄存器地址映射
    gpioe_virt = ioremap(GPIOE_FAN, sizeof(gpio_t));
    if (gpioe_virt == NULL)
    {
        printk("gpioe virt ioremap is error\n");
        return -EIO;
    }
    // RCC_tim1 的使能映射
    rcc_tim1 = ioremap(RCC_TIM1, 4);
    if (rcc_tim1 == NULL)
    {
        printk("rcc tim1 ioremap is error\n");
        return -EIO;
    }
    // tim1 的映射
    tim1_virt = ioremap(TIM1_FAM, sizeof(tim1_t));
    if (tim1_virt == NULL)
    {
        printk("tim1 virt ioremap is error\n");
        return -EIO;
    }
    // 提交目录信息 class_create
    cls = class_create(THIS_MODULE, CNAME);
    if (IS_ERR(cls)) // 判断错误码转换为地址是否在4K空间内
    {
        printk("class create is error\n");
        return PTR_ERR(cls); // 将地址转换为错误码
    }
    // 4.提交设备节点信息 device_create 节点名字myled
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, CNAME);
    if (IS_ERR(dev)) // 判断错误码转换为地址是否在4K空间内
    {
        printk("device create is error\n");
        return PTR_ERR(dev); // 将地址转换为错误码
    }

    // 初始化
    *rcc_virt |= (0x1 << 4);             // 设置GPIOE组时钟使能[4] = 1
    gpioe_virt->MODER &= (~(0x3 << 18)); // 设置pe9引脚为输出模式[19:18] = 01
    gpioe_virt->MODER |= (0x1 << 18);
    gpioe_virt->ODR &= (~(0x1 << 18)); // 设置pe9引脚输出低电平[9] = 0
    *rcc_tim1 |= (0x1);                // 设置tim1时钟使能
    // 将PE9设置为复用功能-----0x10
    gpioe_virt->MODER &= (~(0x3 << 18));
    gpioe_virt->MODER |= (0x2 << 18);
    // 将复用功能设置为TIM1_CH1功能 ----[7:4] 0001
    gpioe_virt->AFRH &= (~(0xf << 4));
    gpioe_virt->AFRH |= (0x1 << 4);
    // 设置自动装载缓存模式 ARPE位
    tim1_virt->CR1 |= (0x1 << 7);
    // 设置计数器为边缘校准并且为递减状态---[6:5]--0x00  [4]--0x1
    tim1_virt->CR1 &= (~(0x3 << 5));
    tim1_virt->CR1 |= (0x1 << 4);
    // 设置TIM1_CH1口为PWM输出模式  16,[6:4]--0b0110
    tim1_virt->CCMR1 &= (~(0x1 << 16));
    tim1_virt->CCMR1 &= (~(0x7 << 4));
    tim1_virt->CCMR1 |= (0x6 << 4);
    // 设置通道1用于输出     [1:0]--0x0
    tim1_virt->CCMR1 &= (~(0x3));
    // 设置默认输出极性
    tim1_virt->CCER &= (~(0x1 << 3));
    tim1_virt->CCER |= (0x1 << 1);

    return 0;
}
static void __exit fan_exit(void)
{
    // 主要输出使能
    tim1_virt->BDTR &= (~(0x1) << 15);
    // 设置比较寄存器的使能
    tim1_virt->CCMR1 &= (~(0x1) << 3);
    // 设置管脚输出使能
    tim1_virt->CCER &= ~(0x1);
    // 设置计数器使能
    tim1_virt->CR1 &= ~(0x1);

    iounmap(rcc_virt);
    iounmap(gpioe_virt);
    iounmap(rcc_tim1);
    iounmap(tim1_virt);

    device_destroy(cls, MKDEV(major, 0)); // 取消向上层提交设备节点信息
    class_destroy(cls);                   // 取消向上层提交目录信息

    // 注销字符设备驱动
    unregister_chrdev(major, CNAME);
}
module_init(fan_init);
module_exit(fan_exit);
MODULE_LICENSE("GPL");
#ifndef __MYLED_H__
#define __MYLED_H__
//
typedef struct{
	volatile unsigned int CR1; 
	volatile unsigned int CR2;
	volatile unsigned int SMCR;
	volatile unsigned int DIER;
	volatile unsigned int SR;
	volatile unsigned int EGR;
	volatile unsigned int CCMR1;
	volatile unsigned int CCMR2;
	volatile unsigned int CCER;
	volatile unsigned int CNT;
	volatile unsigned int PSC;
	volatile unsigned int ARR;
	volatile unsigned int RCR;
	volatile unsigned int CCR1;
	volatile unsigned int CCR2;
	volatile unsigned int CCR3;
	volatile unsigned int CCR4;
	volatile unsigned int BDTR;
	volatile unsigned int DCR;
	volatile unsigned int DMAR;
	volatile unsigned int Res1;
	volatile unsigned int CCMR3;
	volatile unsigned int CCR5;
	volatile unsigned int CCR6;
	volatile unsigned int AF1;
	volatile unsigned int AF2;
	volatile unsigned int TISEL;
} tim1_t;

//封装GPIO寄存器
typedef struct {
    volatile unsigned int MODER;   // 0x00
    volatile unsigned int OTYPER;  // 0x04
    volatile unsigned int OSPEEDR; // 0x08
    volatile unsigned int PUPDR;   // 0x0C
    volatile unsigned int IDR;     // 0x10
    volatile unsigned int ODR;     // 0x14
    volatile unsigned int BSRR;    // 0x18                                                                        
    volatile unsigned int LCKR;    // 0x1C 
    volatile unsigned int AFRL;    // 0x20 
    volatile unsigned int AFRH;    // 0x24
    volatile unsigned int BRR;     // 0x28
    volatile unsigned int res;
    volatile unsigned int SECCFGR; // 0x30
}gpio_t;

#define  GPIOE_FAN   0x50006000  //GPIOE组物理地址
#define  RCC_PHY_ADDR  0x50000A28 //RCC物理地址
#define  RCC_TIM1  0x50000A08 //RCC APB2总线
#define  TIM1_FAM 0x44000000 // tim1

#define ONE_FAN _IOW('c',1,int)
#define TWO_FAN _IOW('c',2,int)
#define THREE_FAN _IOW('c',3,int)
#define CLOSE_FAN _IOW('c',4,int)

#endif

👆开发板风扇驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
 #include "led.h"
 #define CNAME "myled"
struct class *cls;
struct device *dev;
unsigned int major = 0;


struct device_node *node;
char *name[3] = {"led1", "led2", "led3"};
struct gpio_desc* edesc[3];//扩展板的结构体指针数组
struct device_node *enode;
int myled_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
 long myled_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{
    int whitch;
    int ret;
    //判断cmd
    switch(cmd) 
    {
    case LED_ON:
        //将用户空间数据传递给内容空间
        ret = copy_from_user(&whitch,(void*)args,sizeof(int));
        printk("led whitch = %d\n",whitch);
        if(ret)
        {
            printk("copy from user error\n");
            return-EIO;
        }
        printk("led:%s:%s:%d\n",__FILE__,__func__,__LINE__);
        switch(whitch){ //判断操作哪一盏灯
            case LED1:
                gpiod_set_value(edesc[0],1); //LED1点亮
                printk("here is led1\n");
                break;
            case LED2:
                 gpiod_set_value(edesc[1],1); //LED2点亮
                printk("here is led2\n");
                break;
            case LED3:
                 gpiod_set_value(edesc[2],1);  //LED3点亮
                printk("here is led3\n");
                break;
        }
        break;
    case LED_OFF:
        //将用户空间数据传递给内容空间
        ret = copy_from_user(&whitch,(void*)args,sizeof(int));
        if(ret){
            printk("copy to user is error\n");
            return -EIO;
        }
        switch(whitch){ //判断操作哪一盏灯
            case LED1:
                gpiod_set_value(edesc[0],0); //LED1熄灭
                break;
            case LED2:
                 gpiod_set_value(edesc[1],0); //LED2熄灭
                break;
            case LED3:
                gpiod_set_value(edesc[2],0);  //LED3熄灭
                break;
        }    
        break;    
    default:
        break;
    }
    return 0;

}
int myled_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
const struct file_operations fops = {
    .open = myled_open,
    .unlocked_ioctl = myled_ioctl,
    .release =myled_close, 
};
// 入口 安装驱动时LED灯点亮
static int __init mycdev_init(void)
{
    int i;
   
    // 获取到设备树myled节点
    node = of_find_node_by_path("/myled");
    if(node == NULL)
    {
        printk("of find node by path is error\n");
        return -EIO;
    }

    for (i = 0; i < 3; i++)
    {

        edesc[i] = gpiod_get_from_of_node(node, name[i], 0, GPIOD_OUT_LOW, NULL);//扩展板的结构体指针
        if(IS_ERR(edesc[i])){
            printk("gpiod get from of enode is error\n");
            return PTR_ERR(edesc[i]);
        }
        gpiod_set_value(edesc[i],0); //设置扩展板输出高电平
    }
       //注册字符设备驱动
    major = register_chrdev(0,CNAME,&fops);
    if(major < 0){
        printk("register chrdev is error\n");
        return major;
    }
    printk("major = %d\n",major); //打印主设备号

        //向上层提交目录信息 /sys/class
    cls = class_create(THIS_MODULE,CNAME);
    if(IS_ERR(cls)){ //判断地址是否存在4K空间
        printk("class create is error\n");
        return PTR_ERR(cls); //将错误码指针转换为错误码
    }
    //向上层提交设备节点信息
    dev = device_create(cls,NULL,MKDEV(major,0),NULL,CNAME);
    if(IS_ERR(dev)){ //判断地址是否存在4K空间
        printk("class create is error\n");
        return PTR_ERR(dev); //将错误码指针转换为错误码
    }
    return 0;
}

// 出口 写在驱动 LED灯熄灭
static void __exit mycdev_exit(void)
{
    int i;
    for (i = 0; i < 3; i++)
    {
       gpiod_set_value(edesc[i], 0); //设置gpio引脚输出的值
       gpiod_put(edesc[i]);
    }
     device_destroy(cls,MKDEV(major,0)); //取消向上层提交设备节点信息
    class_destroy(cls); //取消向上层提交目录信息 
    //注销字符设备驱动
    unregister_chrdev(major,CNAME);
}

module_init(mycdev_init); // 指定入口地址
module_exit(mycdev_exit); // 指定出口地址
MODULE_LICENSE("GPL");    // 许可证
#ifndef __LED_H__
#define __LED_H__


#define PHY_RCC 0x50000A28 //RCC基地址
#define PHY_GPIOB 0x50003000//GPIOB组基地址
#define PHY_GPIOE 0x50006000//GPIOE组基地址
#define PHY_GPIOF 0x50007000 //GPIOF组基地址
//命令码封装
#define LED_ON _IOW('a', 1,int)//灯亮
#define LED_OFF _IOW('a', 0,int)//灯灭

#define GET_si7006_SHI _IOW('c',0,int)//湿度
#define GET_si7006_WEN _IOR('c',1,int)//温度

#define GET_CMD_SIZE(cmd) ((cmd >> 16) & 0x3fff)//获取命令码大小
#define SI7006_SHI 0xE5//湿度
#define SI7006_WEN 0XE3//温度

#define SEG_WHICH _IOR('d',0,int)//位
#define SEG_DAT _IOW('d',1,int)//段

#define SET_FAN_PWM _IOR('f', 1, int)//风扇
#define SET_MATOR_PWM _IOR('m', 1, int)//马达
#define SET_BEEP_PWM _IOR('b', 1, int)//蜂鸣器

enum{
    LED1,
    LED2,
    LED3,
};
typedef struct {
    volatile unsigned int MODER;   // 0x00
    volatile unsigned int OTYPER;  // 0x04
    volatile unsigned int OSPEEDR; // 0x08
    volatile unsigned int PUPDR;   // 0x0C
    volatile unsigned int IDR;     // 0x10
    volatile unsigned int ODR;     // 0x14
    volatile unsigned int BSRR;    // 0x18
    volatile unsigned int LCKR;    // 0x1C                                                                        
    volatile unsigned int AFRL;    // 0x20 
    volatile unsigned int AFRH;    // 0x24
    volatile unsigned int BRR;     // 0x28
    volatile unsigned int res;
    volatile unsigned int SECCFGR; // 0x30
}gpio_t;
#endif

👆利用gpio实现的led灯驱动部分

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include "cJSON.h"

#include "si7006.h"
#include "led.h"
#define ERR_MSG(msg) do{\
	fprintf(stderr,"__%d__",__LINE__);\
	perror(msg);\
} while(0)
#define PORT 8888		   // 端口号的网络字节序,1024~49151
#define IP "192.168.1.100" // 本机IP,ifconfig


#define PHY_RCC 0x50000A28 //RCC基地址
#define PHY_GPIOB 0x50003000//GPIOE组基地址
#define PHY_GPIOE 0x50006000//GPIOE组基地址
#define PHY_GPIOF 0x50007000 //GPIOF组基地址



// #define SER_PORT 8888 //服务器端口
// #define SER_IP "192.168.1.250" //服务器ip地址
//命令码封装
#define LED_ON _IOW('a', 1,int)//灯亮
#define LED_OFF _IOW('a', 0,int)//灯灭
#define SEG_TEMP_HUM _IOR('c', 0, int)//温度
#define SEG_HUM _IOR('c', 1, int)//湿度
#define SET_FAN_PWM _IOR('f', 1, int)//风扇
#define SET_MATOR_PWM _IOR('m', 1, int)//马达
#define SET_BEEP_PWM _IOR('b', 1, int)//蜂鸣器
#define GET_SI7006_TMEP  _IOR('a',0,int) //读取温度命令码
#define GET_SI7006_HUM  _IOR('a',1,int) //读取湿度命令码
#define GET_CMD_SIZE(cmd) ((cmd >> 16) & 0x3fff) //获取命令码大小
#define TEMP_REG 0xE3 //读取温度地址
#define HUM_REG 0XE5 //读取湿度地址
//控制风扇挡位
#define ONE_FAN _IOW('c',1,int)
#define TWO_FAN _IOW('c',2,int)
#define THREE_FAN _IOW('c',3,int)
#define CLOSE_FAN _IOW('c',4,int)



int ret_recv;
int ret_send;
int newfd;
void* temp_hum(void*);//温湿度线程回调函数
int flages;
int fd_t;
int fd1_t;
//int max_temp,max_hum;//温湿度阈值
int set_LED_fun(int num);
//LED1灯的操作
int set_LED1_fun(int num);
//LED2灯的操作
int set_LED2_fun(int num);
//LED3灯的操作
int set_LED3_fun(int num);
//蜂鸣器操作
int set_Feng_fun(int num);
//风扇操作
int set_Wind_fun(int num);
/*//马达操作
int set_Md_fun(int num);*/


#endif

 👆我的头文件

#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include "pwm.h"

#define PWM_MAX 10000
int pwm = 0;
struct pwm_device *pwm_fan = NULL, *pwm_mator = NULL, *pwm_beep = NULL;
struct pwm_state state;
#define CNAME "pwm-fan"
char kbuf[16] = "";
// 分布实现字符设备相关
struct cdev* cdev = NULL;
dev_t devn = -1;

// 自动创建设备节点相关
struct class* cls = NULL;
struct device* dev = NULL;

ssize_t my_write(struct file* file, const char __user* ubuf, size_t size, loff_t* loffs)
{
    
    return size;
}

long my_ioctl(struct file* file, unsigned int cmd, unsigned long args)
{
    switch (cmd) {
    case SET_FAN_PWM://风扇
        pwm = PWM_MAX / 100 * args;
        state.duty_cycle = pwm;
        pwm_apply_state(pwm_fan, &state);
        break;
    case SET_BEEP_PWM://蜂鸣器
        pwm = PWM_MAX / 100 * args;
        state.duty_cycle = pwm;
        pwm_apply_state(pwm_beep, &state);
        break;
    case SET_MATOR_PWM://马达
        pwm = PWM_MAX / 100 * args;
        state.duty_cycle = pwm;
        pwm_apply_state(pwm_mator, &state);
        break;
    }

    return 0;
}
int my_close(struct inode* inode, struct file* file)
{
    //pwm_disable(pwm_mator);
    //pwm_disable(pwm_fan);
    //pwm_disable(pwm_beep);
    return 0;
}
const struct file_operations fops = {
    .unlocked_ioctl = my_ioctl,
    .write = my_write,
    .release = my_close,
};
static int my_pwm_probe(struct platform_device* pdev)
{
    struct device_node* fan_node;
    struct device_node* mator_node;
    struct device_node* beep_node;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 获取风扇节点
    fan_node = of_find_node_by_path("/fan");
    if (!fan_node) {
        printk("__%d__:of_find_node_by_path is error\n", __LINE__);
        return -1;
    }
    // 获取马达节点
    mator_node = of_find_node_by_path("/vibrator");
    if (!fan_node) {
        printk("__%d__:of_find_node_by_path is error\n", __LINE__);
        return -1;
    }
    // 获取蜂鸣器节点
    beep_node = of_find_node_by_path("/beeper");
    if (!fan_node) {
        printk("__%d__:of_find_node_by_path is error\n", __LINE__);
        return -1;
    }
    // 获取马达PWM
    pwm_mator = devm_of_pwm_get(&pdev->dev, mator_node, NULL);
    if (IS_ERR(pwm_mator)) {
        printk("__%d__:devm_of_pwm_get is error\n", __LINE__);
        return PTR_ERR(pwm_mator);
    }
    // 获取风扇PWM
    pwm_fan = devm_of_pwm_get(&pdev->dev, fan_node, NULL);
    if (IS_ERR(pwm_fan)) {
        printk("__%d__:devm_of_pwm_get is error\n", __LINE__);
        return PTR_ERR(pwm_fan);
    }
    // 获取蜂鸣器PWM
    pwm_beep = devm_of_pwm_get(&pdev->dev, beep_node, NULL);
    if (IS_ERR(pwm_beep)) {
        printk("__%d__:devm_of_pwm_get is error\n", __LINE__);
        return PTR_ERR(pwm_beep);
    }
    pwm_init_state(pwm_fan, &state);
    pwm_init_state(pwm_beep, &state);
    pwm_init_state(pwm_mator, &state);
    state.period = PWM_MAX;
    state.duty_cycle = pwm;
    state.enabled = true;

    /**********分布实现字符设备**************/
    cdev = cdev_alloc();
    if (!cdev) {
        printk("__%d__:cdev_alloc is error\n", __LINE__);
        goto ERR1;
    }
    cdev_init(cdev, &fops); // 初始化对象
    // 动态分配对象
    if (alloc_chrdev_region(&devn, 0, 1, CNAME)) {
        printk("__%d__:alloc_chrdev_region is error\n", __LINE__);
        goto ERR2;
    }
    // 注册对象
    if (cdev_add(cdev, devn, 1)) {
        printk("__%d__:cdev_add is error\n", __LINE__);
        goto ERR3;
    }
    /**********自动创建设备节点**************/
    cls = class_create(THIS_MODULE, CNAME);
    if (IS_ERR(cls)) {
        printk("__%d__:class_create is error\n", __LINE__);
        goto ERR4;
    }
    dev = device_create(cls, NULL, devn, NULL, CNAME);
    if (IS_ERR(dev)) {
        printk("__%d__:device_create is error\n", __LINE__);
        goto ERR5;
    }
    return 0;

ERR5:
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(devn, 1);
ERR2:
    kfree(cdev);
ERR1:
    return -1;
    return 0;
}

static int my_pwm_remove(struct platform_device* pdev)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    pwm_disable(pwm_fan);
    pwm_disable(pwm_mator);
    pwm_disable(pwm_beep);
    pwm_free(pwm_fan);
    pwm_free(pwm_mator);
    pwm_free(pwm_beep);

    device_destroy(cls, devn);
    class_destroy(cls);

    cdev_del(cdev); // 注销对象
    unregister_chrdev_region(devn, 1);
    kfree(cdev);
    return 0;
}

static const struct of_device_id my_pwm_of_match[] = {

    {
        .compatible = "hqyj,fan",
    },

    {},
};
MODULE_DEVICE_TABLE(of, my_pwm_of_match);

static struct platform_driver my_pwm_driver = {
    .driver = {
        .name = "my_pwm_driver",
        .of_match_table = my_pwm_of_match,
    },
    .probe = my_pwm_probe,
    .remove = my_pwm_remove,
};

module_platform_driver(my_pwm_driver);
MODULE_LICENSE("GPL");

👆利用pwm实现的风扇马达蜂鸣器驱动(头文件不展示了)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include "spi.h"
int major;
int a,b,c,d;
int data;
struct class *cls;
struct device *dev;
struct spi_device *gspi;
struct work_struct work;//分配工作队列对象
void my_work(struct work_struct* work1)//工作队列函数
{
    int x = 0;
    int hum = (data >> 16) & 0xFFFF;
    int temp = data & 0xFFFF;
    a = hum / 10;
    b = hum % 10;
    c = temp / 10;
    d = temp % 10;
    //printk("a = %d b = %d c = %d d = %d\n",a,b,c,d);
    //工作队列函数
    spi_write(gspi,&which[x++],1);//亮第一个数码管
    spi_write(gspi,&code[a],1);//显示温度第一个值
    mdelay(1);
    spi_write(gspi,&which[x++],1);//亮第二个数码管
    spi_write(gspi,&code[b],1);//显示温度第二个值
    mdelay(1);
    spi_write(gspi,&which[x++],1);//亮第三个数码管
    spi_write(gspi,&code[c],1);//显示湿度第一个值
    mdelay(1);
    spi_write(gspi,&which[x++],1);//亮第四个数码管
    spi_write(gspi,&code[d],1);//显示湿度第二个值
    mdelay(1);
    if(x >= 4) x=0;

    schedule_work(&work);//调用执行
}
int myopen(struct inode *inod, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

int myclose(struct inode *inod, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    cancel_work_sync(&work);//注销队列
    return 0;
}

long myioctl(struct file *file, unsigned int cmd, unsigned long args)
{  
    data = args;
    schedule_work(&work);//调用执行
    return 0;
}
struct file_operations fops = {
    .open = myopen,
    .release = myclose,
    .unlocked_ioctl = myioctl,
};


//匹配成功执行probe函数
int	spi_probe(struct spi_device *spi)
{
    char buf[] = {0xf,0x0};
    gspi = spi;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
     spi_write(spi,buf,ARRAY_SIZE(buf));
    // 注册字符设备
    major = register_chrdev(0, "m74hc595", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        return major;
    }
    printk("注册字符设备驱动成功\n");
    // 自动创建设备节点
    // 向上提交目录
    cls = class_create(THIS_MODULE, "m74hc595");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");
    // 向上提交节点信息
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "m74hc595");
    if (IS_ERR(dev))
    {
        printk("向上提交节点信息失败\n");
        return PTR_ERR(dev);
    }
    printk("向上提交节点成功\n");
    INIT_WORK(&work,my_work);//初始化
    return 0;
}
//卸载成功执行remove函数
int	spi_remove(struct spi_device *spi)
{
    spi_write(gspi,0,1);//灭数码管
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    device_destroy(cls,MKDEV(major,0));
    class_destroy(cls);
    unregister_chrdev(major,"m74hc595");//注销设备号
    cancel_work_sync(&work);//注销队列
    flush_scheduled_work();//等待工作队列完成
    return 0;
}

struct of_device_id spi_match_table[] = {
    {.compatible = "hqyj,m74hc595",},
    {},//防止数组越界
};

//定义结构体,通过设备树匹配
struct spi_driver m74hc595 = {
    .probe = spi_probe,
    .remove = spi_remove,
    .driver = {
        .name = "hqyj,m74hc595",
        .of_match_table = spi_match_table,
    },
};


//一键宏
module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");

利用spi实现的数码管驱动部分(头文件不展示了)

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值