文章目录

  • 1. 基本原理
  • 2. 计算方法
  • 3. c语言代码实现
  • 4. SHT30代码
    • 4.1 drv.c
    • 4.2 test.c
    • 4.3 Makefile

1. 基本原理

 循环冗余校验码(CRC)的基本原理是:在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码又叫(N,K)码。对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。

2. 计算方法

 1. 预置一个值为0xFFFF的16位寄存器,此寄存器为CRC寄存器
 2. 把第一个8位二进制数与16位的CRC寄存器相异或,异或的结果存在CRC寄存器中
 3. CRC寄存器的内容右移一位,用0填补最高位,并检测移出位是0还是1
 4. 如果移出位是0,则重复步骤3
  如果移出位是1,则与多项式进行异或
 5. 重复步骤3、4,直到右移8位,这样整个8位数据都进行了处理
 6. 重复步骤2~5,进行下一个字节的处理
 7. 最后得到的CRC寄存器的内容即为CRC校验码

3. c语言代码实现

 以SHT30温湿度传感器为例,对CRC校验的过程进行代码实现,其中SHT30 CRC检验的相关信息如下图。从图中可以看出:该传感器采用的是CRC8校验,多项式位x8+x5+x4+1,对应的代码为1 0011 0001
 而CRC校验码的位数=多项式的位数-1
 多项式位数=最高次幂+1
 所以得到CRC多项式校验码是0x31,手册中还给到了一个示例,数据是0xBEEF时,生成的校验码是0x92,

以下是crc8的代码实现,对于crc16,crc32或者其他多项式的校验,只需要更改代码9行和10行的初始值即可。

#include <stdio.h>
typedef unsigned char uint8_t;/** crc8校验函数,data为要校验的数据,len为要校验的数据的字节数*/
uint8_t crc8(const uint8_t *data, int len)
{const uint8_t POLYNOMIAL = 0x31;uint8_t crc = 0xFF;int i, j;for (i=0; i<len; ++i) {crc ^= *data++;for (j=0; j<8; ++j) {crc = ( crc & 0x80 )? (crc << 1) ^ POLYNOMIAL: (crc << 1);}}return crc;
}int main(int argc, const char *argv[])
{unsigned char data1[2] = {0x61, 0x04};unsigned char data2[2] = {0xBE, 0xEF};printf("0x%02X\n", crc8(data1, 2));printf("0x%02X\n", crc8(data2, 2));return 0;
}
/* 输出结果
linux@linux-VirtualBox:~$ ./a.out
0xE4
0x92
*/

4. SHT30代码

 SHT30传感器芯片手册连接

4.1 drv.c

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/device.h>#include <uapi/asm-generic/errno-base.h>#define SHT30_MAJOR 255
#define SHT30_MINOR 0
#define SHT30_NAME "mpu6050_cdev"struct sht30_dev{struct i2c_client *client;struct cdev cdev;
};struct class  *cls = NULL;
struct device *dev = NULL;static int sht30_open(struct inode *inode, struct file *filp)
{struct sht30_dev *sht30 = container_of(inode->i_cdev, struct sht30_dev, cdev);filp->private_data = sht30;printk("%s -- %d.\n", __FUNCTION__, __LINE__);return 0;
}static int sht30_release(struct inode *inode, struct file *filp)
{printk("%s -- %d.\n", __FUNCTION__, __LINE__);return 0;
}static ssize_t sht30_read(struct file *filp, char __user *userbuf, size_t size, loff_t *offset)
{unsigned char buf[6];int ret;struct sht30_dev *sht30 = filp->private_data;//   printk("%s -- %d.\n", __FUNCTION__, __LINE__);ret = i2c_master_recv(sht30->client, buf, 6);if (ret < 0){printk("i2c_master_recv failed.\n");return ret;}printk("0X%02X 0X%02X 0X%02X 0X%02X 0X%02X 0X%02X.\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);ret = copy_to_user(userbuf, buf, sizeof(buf));if (ret < 0){printk("copy_to_user failed.\n");return ret;}return ret;
}static ssize_t sht30_write(struct file *filp, const char __user *userbuf, size_t size, loff_t *offset)
{unsigned char buf[2];int ret;struct sht30_dev *sht30 = filp->private_data;//   printk("%s -- %d.\n", __FUNCTION__, __LINE__);ret = copy_from_user(buf, userbuf, size);if (ret < 0){printk("copy_from_user failed.\n");return ret;}ret = i2c_master_send(sht30->client, buf, size);if (ret < 0){printk("i2c_master_send failed.\n");return ret;}return ret;
}const struct file_operations sht30_ops = {.open = sht30_open,.release = sht30_release,.read = sht30_read,.write = sht30_write,
};static int sht30_probe(struct i2c_client *client, const struct i2c_device_id *id)
{dev_t dev_no;int ret;struct sht30_dev *sht30;printk("%s -- %d.\n", __FUNCTION__, __LINE__);printk("%p.\n", client);dev_no = MKDEV(SHT30_MAJOR, SHT30_MINOR);ret = register_chrdev_region(dev_no, 1, SHT30_NAME);if ( ret ){printk("register_chrdev_region failed.\n");goto reg_err;}sht30 = kzalloc(sizeof(struct sht30_dev), GFP_KERNEL);    /* GFP_KERNEL = 0 */if ( IS_ERR(sht30) )       /* 判断指针是否有误 */{printk("kzalloc failed.\n");ret = -PTR_ERR(sht30);    /* 返回错误码 ,在include/uapi/asm-generic/errno-base.h中定义 */goto kzalloc_err;}i2c_set_clientdata(client, sht30);   /* 把数据保存到 client->dev.driver_data */sht30->client = client;cdev_init(&sht30->cdev, &sht30_ops);ret = cdev_add(&sht30->cdev, dev_no, 1);if ( ret ){printk("cdev_add failed.\n");goto add_err;}cls = class_create(THIS_MODULE, "sht30_cls");if ( IS_ERR(cls) ){printk("class_create failed.\n");ret = PTR_ERR(cls);goto cls_err;}dev = device_create(cls, NULL, dev_no, NULL, "sht30dev%d", 0);if ( IS_ERR(dev) ){printk("device_create failed.\n");ret = PTR_ERR(dev);goto dev_err;}return 0;dev_err:class_destroy(cls);
cls_err:cdev_del(&sht30->cdev);
add_err:kfree(sht30);
kzalloc_err:unregister_chrdev_region(dev_no, 1);
reg_err:return ret;
}static int sht30_remove(struct i2c_client *client)
{dev_t dev;struct sht30_dev *sht30;printk("%s -- %d.\n", __FUNCTION__, __LINE__);printk("%p.\n", client);dev = MKDEV(SHT30_MAJOR, SHT30_MINOR);sht30 = i2c_get_clientdata(client);    /* client->dev.driver_data */device_destroy(cls, dev);class_destroy(cls);cdev_del(&sht30->cdev);kfree(sht30);unregister_chrdev_region(dev, 1);return 0;
}struct i2c_device_id sht30_id[] = {{.name = "sht30"},{}
};struct i2c_driver sht30_driver = {.probe  = sht30_probe,.remove = sht30_remove,.driver = {.name  = "my_i2cdrv",.owner = THIS_MODULE, },.id_table = sht30_id,
};static int __init i2c_init(void)
{return i2c_add_driver(&sht30_driver);
}static void __exit i2c_exit(void)
{i2c_del_driver(&sht30_driver);
}module_init(i2c_init);
module_exit(i2c_exit);
MODULE_LICENSE("GPL");

4.2 test.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>const char *sht30_pathname = "/dev/sht30dev0";unsigned char crc8(const unsigned char *data, int len)
{const unsigned char POLYNOMIAL = 0x31;unsigned char crc = 0xFF;int i, j;for (i=0; i<len; ++i) {crc ^= *data++;for (j=0; j<8; ++j) {crc = ( crc & 0x80 )? (crc << 1) ^ POLYNOMIAL: (crc << 1);}}return crc;
}int main()
{int fd, i = 0, flag = 0;unsigned char write_buf[] = {0x2C, 0x06};unsigned char read_buf[6] = {0};fd = open(sht30_pathname, O_RDWR, 0666);if (fd < 0){printf("open failed\n");return -1;}/* init */while (1){do{write(fd, write_buf, sizeof(write_buf));read(fd, read_buf, sizeof(read_buf));         }while ( !(crc8(read_buf, 2)==read_buf[2] && crc8(read_buf+3, 2)==read_buf[5]) );printf("temp = %.3f℃\n", ( 1.0*175*(read_buf[0]*256 + read_buf[1]) / 65535 - 45 ) );printf("humi = %.3f%% \n", ( 1.0*100*(read_buf[3]*256 + read_buf[4]) / 65535 ) );printf("----------------- count = %d\n", ++i);memset(read_buf,0,sizeof(read_buf));if(i == 36000){i = 0;}sleep(1);}close(fd);return 0;
}

4.3 Makefile

KERNELDIR ?= /home/linux/ti-processor-sdk-linux-am335x-evm-05.02.00.10/board-support/linux-4.14.79/
PWD := $(shell pwd)all:make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNELDIR) M=$(PWD) modulesarm-linux-gnueabihf-gcc test.c -o app
install:sudo cp *.ko  app /tftpbootmake ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNELDIR) M=$(PWD) cleanrm app
clean:make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNELDIR) M=$(PWD) cleanrm appobj-m += drv.o

CRC校验——以SHT30温湿度传感器为例(内附SHT30的驱动代码)相关推荐

  1. sht30温湿度传感器中文手册_【STM32Cube_16】使用硬件CRC校验数据(以SHT30为例)...

    寻求更好的阅读体验,请移步Mculover666的个人博客: Mculover666的个人博客​www.mculover666.cn 本篇详细的记录了如何使用STM32CubeMX配置STM32L43 ...

  2. 模拟IIC读取SHT30温湿度传感器数据

    文章目录 1 i2c.c 2 i2c.h 3 crc.c 4 crc.h 1 i2c.c /*** @brief SHT30温湿度传感器相关,使用模拟IIC进行数据的读取*/#include < ...

  3. 传感器:SHT30温湿度传感器检测环境温湿度实验(底部附代码)

    一.导言 SHT30温湿度传感器模块是通过IIC驱动,所以大家使用该模块时,需要具备IIC的基本知识,这篇文章带领大家一起使用SHT30模块进行温湿度的测量,当然DHT10/DHT10原理都一样,好了 ...

  4. STM32F103使用硬件IIC驱动SHT30温湿度传感器

    文章目录 前言 一.SHT30温湿度传感器原理图 二.代码部分 1.SHT30.c文件 2.SHT30.h文件 总结 前言 SHT30是一种常见的温湿度传感器,该传感器广泛应用于各种场景,小米的温湿度 ...

  5. 【STM32】【STM32CubeMX】STM32CubeMX的使用之四:IIC总线协议驱动SHT30温湿度传感器

    文章目录 0.前言 1.传感器介绍 1.1.传感器简介 1.2.传感器板原理图 1.3.传感器引脚定义 1.4.数据采集工作流程 1.4.1.单次数据采集模式 1.4.2.周期型数据采集模式 1.5. ...

  6. SHT30温湿度传感器应用笔记

    芯片介绍 SHT30是一款温湿度传感器,使用IIC通信接口.可根据命令设置其测量频率.测量时间:测量持续时间有三种可选(见芯片手册2.2): HIGH:12.5ms: medium:4.5ms: lo ...

  7. nRF52笔记(8) IIC读取sht30温湿度传感器

    1.平台的条件 1.1 软件平台:sdk14.2 1.2 硬件平台: nrf52832 2 说明: 只是介绍代码怎么使用,直接点 QQ: 1297311998 ,如果有什么问题,请高手不吝赐教 2.n ...

  8. STM32模拟IIC驱动sht30温湿度传感器

    最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了 所以拿出来分享给大家. sht30外观 驱动不是自己写的, 是采用CSDN上的一位朋友的 , ...

  9. 学习记录 | SHT30温湿度传感器显示异常

    使用的单片机是STC12C5A60S2,SHT30驱动程序直接照搬的这位博主SHT3X 温湿度模块 C51驱动 --简单调用获取温湿度信息_往漓的博客-CSDN博客SHT3X 温湿度模块 C51驱动S ...

最新文章

  1. 异构服务器 微服务_Spring Cloud Alibaba Sidecar 多语言微服务异构
  2. 使系统生成50个0-9之间的随机数,将每个数字出现的次数 存入一个一维数组中,统计出现次数最多和出现次数最少的数字,及出现次数 和出现频率。...
  3. Android之如何解决Android Studio左边的的project不见了
  4. 计算机二级选择题40分,2017年计算机二级选择题及答案
  5. 环形单链表的约瑟夫问题
  6. elasticsearch配置优化
  7. 谁“玩死了”共享单车?
  8. c语言名著摘抄——语法及实例
  9. node ajax实现登录注册,nodejs实现简易登录注册
  10. 大数据之路阿里巴巴实践
  11. 智力答题源码php,基于PHP智力竞赛抢答计分系统PHP1025(毕业设计+论文)
  12. Matlab 多行屏蔽或注释方法
  13. php codesniffer,为你的 PHP_CodeSniffer 构建自定义规则
  14. circos 作图简介
  15. 视频丨中兴通讯齐聚全球合作伙伴的力量 拥抱最好的时代
  16. 局域网、网段、子网的区别
  17. 安卓linux病毒,如何清除linux病毒
  18. python爬虫教材推荐 豆瓣_Python爬虫入门教程:豆瓣Top电影爬取
  19. TypeError: can only concatenate str (not “bytes“) to str
  20. java9 gc log参数迁移_个人文章 - SegmentFault 思否

热门文章

  1. Dockerfile说明
  2. 论文笔记-对话系统综述
  3. Msg 15138 The database principal owns a schema in the database, and cannot be dropped.
  4. 黑白双轨棋·改编(定子棋,终盘换子,在计算赢子的多少)
  5. 2021年二级c语言采用的版本是,2021年二级c语言笔试必背-20210416065706.doc-原创力文档...
  6. 最全MySQL基础篇
  7. 数学归纳法求证欧几里得算法
  8. java数组初始化0_Java自学-数组 初始化数组
  9. svn查看ip linux,查看svn服务器的ip地址
  10. linux arm xenomai,Wiki - Xenomai