• 驱动开发,使用数码管显示采集的温湿度的值(取整)


    1.IIC驱动层次图(同SPI)

            前提:将核心层和总线驱动层配置进内核;

            先完成设备驱动和i2c总线驱动的绑定,让总线驱动管理到设备驱动,调用核心层API即可完成绑定,然后i2c总线驱动完成设备驱动和si7006的匹配, 最后设备驱动通过IIC控制器完成si7006设备的温湿度的采集,最后将采集的温湿度显示在数码管上;

    2.代码

    ---head.h---头文件
    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. #define GET_HUM _IOR('m',1,int) //获取湿度的功能码
    4. #define GET_TEM _IOR('m',0,int) //获取温度的功能码
    5. #define GET_TH _IOR('m',2,int)//获取数码管的功能码
    6. #endif
    ---si7006.c---温湿度驱动文件
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/i2c.h>
    4. #include <linux/fs.h>
    5. #include <linux/uaccess.h>
    6. #include <linux/device.h>
    7. #include "head.h"
    8. unsigned int major;
    9. struct class *cls;
    10. struct device *dev;
    11. struct i2c_client *client1;
    12. // 封装函数读取温度和湿度
    13. int read_hum_tem(char reg)
    14. {
    15. // 封装传输的消息
    16. char r_buf[] = {reg};
    17. short value;
    18. struct i2c_msg r_msg[] = {
    19. [0] = {
    20. .addr = client1->addr,
    21. .flags = 0,
    22. .len = sizeof(r_buf),
    23. .buf = r_buf,
    24. },
    25. [1] = {
    26. .addr = client1->addr,
    27. .flags = 1,
    28. .len = 2,
    29. .buf = (char *)&value,
    30. },
    31. };
    32. // 传输消息
    33. int ret = i2c_transfer(client1->adapter, r_msg, 2);
    34. if (ret != 2)
    35. {
    36. printk("传输消息失败\n");
    37. return -EIO;
    38. }
    39. return value;
    40. }
    41. // 封装操作方法
    42. int si7006_open(struct inode *inode, struct file *file)
    43. {
    44. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    45. return 0;
    46. }
    47. long si7006_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    48. {
    49. int tem, hum;
    50. int ret;
    51. switch (cmd)
    52. {
    53. case GET_HUM: // 读取湿度
    54. hum = read_hum_tem(0xE5);
    55. ret = copy_to_user((void *)arg, &hum, 4);
    56. if (ret)
    57. {
    58. printk("copy_to_user err\n");
    59. return ret;
    60. }
    61. break;
    62. case GET_TEM: // 读取湿度
    63. tem = read_hum_tem(0xE3);
    64. ret = copy_to_user((void *)arg, &tem, 4);
    65. if (ret)
    66. {
    67. printk("copy_to_user err\n");
    68. return ret;
    69. }
    70. break;
    71. }
    72. return 0;
    73. }
    74. int si7006_close(struct inode *inode, struct file *file)
    75. {
    76. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    77. return 0;
    78. }
    79. // 定义操作方法结构体遍历并且初始化
    80. struct file_operations fops = {
    81. .open = si7006_open,
    82. .unlocked_ioctl = si7006_ioctl,
    83. .release = si7006_close,
    84. };
    85. // 给对象分配空间并初始化
    86. int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
    87. {
    88. client1 = client;
    89. int ret;
    90. // 字符设备驱动注册
    91. major = register_chrdev(0, "si7006", &fops);
    92. if (major < 0)
    93. {
    94. printk("注册字符设备驱动失败\n");
    95. ret = major;
    96. goto out1;
    97. }
    98. printk("注册字符设备驱动成功\n");
    99. // 设备节点的创建
    100. // 向上提交目录
    101. cls = class_create(THIS_MODULE, "si7006");
    102. if (IS_ERR(cls))
    103. {
    104. printk("向上提交目录失败\n");
    105. ret = PTR_ERR(cls);
    106. goto out2;
    107. }
    108. printk("向上提交目录成功\n");
    109. // 向上提交设备节点
    110. dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "si7006");
    111. if (IS_ERR(dev))
    112. {
    113. printk("向上提交设备节点信息失败\n");
    114. ret = PTR_ERR(dev);
    115. goto out3;
    116. }
    117. printk("向上提交设备节点信息成功\n");
    118. return 0;
    119. // 设备信息的获取
    120. out3:
    121. class_destroy(cls);
    122. out2:
    123. unregister_chrdev(major, "si7006");
    124. out1:
    125. return ret;
    126. }
    127. int i2c_remove(struct i2c_client *client)
    128. {
    129. // 设备节点的销毁
    130. device_destroy(cls, MKDEV(major, 0));
    131. // 设备信息的注销
    132. class_destroy(cls);
    133. // 字符设备驱动注销
    134. unregister_chrdev(major, "si7006");
    135. return 0;
    136. }
    137. // 设备树匹配构建
    138. struct of_device_id oftable[] = {
    139. {
    140. .compatible = "hqyj,si7006",
    141. },
    142. {},
    143. };
    144. struct i2c_driver i2c_drv = {
    145. .probe = i2c_probe,
    146. .remove = i2c_remove,
    147. .driver = {
    148. .name = "si7006",
    149. .of_match_table = oftable,
    150. },
    151. };
    152. module_i2c_driver(i2c_drv);
    153. MODULE_LICENSE("GPL");
    ---m74hc595.c---数码管驱动文件
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/spi/spi.h>
    4. #include "head.h"
    5. unsigned int major;
    6. struct class *cls;
    7. struct device *dev;
    8. struct spi_device *spi1 = NULL;
    9. char code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数字
    10. char which[] = {0x8,0x4,0x2,0x1}; //数码管
    11. // 封装操作方法
    12. int m74hc595_open(struct inode *inode, struct file *file)
    13. {
    14. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    15. return 0;
    16. }
    17. long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    18. {
    19. int i,ret;
    20. unsigned int num;
    21. char buf[2]; //存储数字和哪一个数码管
    22. ret = copy_from_user(&num,(void *)arg,4);
    23. if(ret)
    24. {
    25. printk("copy_from_user fail\n");
    26. return -EIO;
    27. }
    28. if(cmd == GET_TH)
    29. {
    30. for(i=0; i<4; i++)
    31. {
    32. buf[1] = code[num%10]; //1234
    33. buf[0] = which[i];
    34. spi_write(spi1, buf, sizeof(buf));
    35. num /= 10;
    36. }
    37. }
    38. return 0;
    39. }
    40. int m74hc595_close(struct inode *inode, struct file *file)
    41. {
    42. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    43. return 0;
    44. }
    45. // 定义操作方法结构体遍历并且初始化
    46. struct file_operations fops = {
    47. .open = m74hc595_open,
    48. .unlocked_ioctl = m74hc595_ioctl,
    49. .release = m74hc595_close,
    50. };
    51. int m74hc595_probe(struct spi_device *spi)
    52. {
    53. spi1 = spi;
    54. int ret;
    55. // 字符设备驱动注册
    56. major = register_chrdev(0, "m74hc595", &fops);
    57. if (major < 0)
    58. {
    59. printk("注册字符设备驱动失败\n");
    60. ret = major;
    61. goto out1;
    62. }
    63. printk("注册字符设备驱动成功\n");
    64. // 设备节点的创建
    65. // 向上提交目录
    66. cls = class_create(THIS_MODULE, "m74hc595");
    67. if (IS_ERR(cls))
    68. {
    69. printk("向上提交目录失败\n");
    70. ret = PTR_ERR(cls);
    71. goto out2;
    72. }
    73. printk("向上提交目录成功\n");
    74. // 向上提交设备节点
    75. dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "m74hc595");
    76. if (IS_ERR(dev))
    77. {
    78. printk("向上提交设备节点信息失败\n");
    79. ret = PTR_ERR(dev);
    80. goto out3;
    81. }
    82. printk("向上提交设备节点信息成功\n");
    83. return 0;
    84. out3:
    85. class_destroy(cls);
    86. out2:
    87. unregister_chrdev(major, "m74hc595");
    88. out1:
    89. return ret;
    90. }
    91. int m74hc595_remove(struct spi_device *spi)
    92. {
    93. // 设备节点的销毁
    94. device_destroy(cls, MKDEV(major, 0));
    95. // 设备信息的注销
    96. class_destroy(cls);
    97. // 字符设备驱动注销
    98. unregister_chrdev(major, "m74hc595");
    99. printk("%s:%d\n", __FILE__, __LINE__);
    100. return 0;
    101. }
    102. // 设备树匹配表
    103. struct of_device_id of_table[] = {
    104. {.compatible = "hqyj,m74hc595"},
    105. {},
    106. };
    107. // 定义SPI对象并且初始化
    108. struct spi_driver m74hc595 = {
    109. .probe = m74hc595_probe,
    110. .remove = m74hc595_remove,
    111. .driver = {
    112. .name = "m74hc595",
    113. .of_match_table = of_table,
    114. },
    115. };
    116. // 一键注册宏
    117. module_spi_driver(m74hc595);
    118. MODULE_LICENSE("GPL");
    ---test.c---测试文件
    1. #include "head.h"
    2. #include <stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/stat.h>
    5. #include <fcntl.h>
    6. #include <unistd.h>
    7. #include <stdlib.h>
    8. #include <string.h>
    9. #include <sys/ioctl.h>
    10. #include <arpa/inet.h>
    11. #include <pthread.h>
    12. int value = 0;
    13. void *temhum_handle(void *arg) // arg = &fd
    14. {
    15. while (1)
    16. {
    17. ioctl(*((int *)arg), GET_TH, &value); // 将温湿度传递给数码管
    18. //printf("%d\n",*((int *)arg));
    19. }
    20. pthread_exit(NULL);
    21. }
    22. int main(int argc, const char *argv[])
    23. {
    24. int tem, hum;
    25. float tem1, hum1;
    26. int fd1 = open("/dev/si7006", O_RDWR);
    27. if (fd1 < 0)
    28. {
    29. printf("设备文件打开失败\n");
    30. exit(-1);
    31. }
    32. int fd2 = open("/dev/m74hc595", O_RDWR);
    33. if (fd2 < 0)
    34. {
    35. printf("设备文件打开失败\n");
    36. exit(-1);
    37. }
    38. // 采用多线程
    39. pthread_t tid;
    40. if (pthread_create(&tid, NULL, temhum_handle, (void *)&fd2) != 0)
    41. {
    42. fprintf(stderr, "pthread_create fail__%d__\n", __LINE__);
    43. return -1;
    44. }
    45. pthread_detach(tid);
    46. while (1)
    47. {
    48. ioctl(fd1, GET_HUM, &hum);
    49. ioctl(fd1, GET_TEM, &tem);
    50. // 大小端转换
    51. hum = ntohs(hum);
    52. tem = ntohs(tem);
    53. // 计算数据
    54. hum1 = 125.0 * hum / 65536 - 6;
    55. tem1 = 175.72 * tem / 65536 - 46.85;
    56. printf("tem = %f,hum = %f\n", tem1, hum1);
    57. value = (int)tem1 * 100 + (int)hum1;
    58. sleep(1);
    59. }
    60. pthread_join(tid, NULL);
    61. return 0;
    62. }

    3.测试现象

  • 相关阅读:
    论文和源码解读:T2I-Adapter: Learning Adapters to Dig out More Controllable Ability
    cartographer_optimization_problem_2d
    spring学习笔记-IOC,AOP,事务管理
    MySQL学习6:索引
    Spring Security
    关于mybatis用${}会sql注入的问题
    阿里p8大佬手写web自动化测试框架教程 涵盖框架源码+视频教程以及搭建流程
    13-ROS参数的学习与使用
    关于使用图表控件LightningChart的十大常见问题及解答
    【深入浅出玩转FPGA学习4----漫谈状态机设计】
  • 原文地址:https://blog.csdn.net/weixin_46260677/article/details/133271607