#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实现的数码管驱动部分(头文件不展示了)