完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
AM2321采用的是单总线控制。 AM2321单总线介绍 查看am2321的数据手册 单总线通信特殊说明
AM2321 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由数据线完成。设备(微处理器)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约 5.1kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫传感器时,传感器才会应答,因此主机访问传感器都必须严格遵循单总线序列,如果出现序列混乱,传感器将不响应主机。 单总线传送数据定义 SDA 用于微处理器与 AM2321 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。具体通信时序如下图1所示,通信格式 如下表1单总线格式所示: 图1 通信时序 表1 单总线格式 单总线数据计算示例 示例一:接收到的 40 位数据为: [tr]0000 00101001 00100000 00010000 11011010 0010[/tr]
湿度: 0000 0010 1001 0010 = 0292H (十六进制)= 2× 256 + 9× 16 + 2 = 658=> 湿度 = 65.8%RH温度: 0000 0001 0000 1101 = 10DH(十六进制) = 1× 256 + 0× 16 + 13 = 269=> 温度= 26.9℃ 单总线时序说明 主机从 AM2321 读取的温湿度数据总是前一次的测量值,如两次测量间隔时间很长,请连续读两次以第二次获得的值为实时温湿度值,同时两次读取间隔时间最小为 2S。 读写的流程图 程序代码编写 添加设备树 在设备树 arch/arm64/boot/dts/rockchip/rk3399pro-toybrick-prop-linux.dts 中添加 gpio-am2321{ status = "okay"; compatible = "gpio-am2321"; gpio-am2321 = <&gpio1 RK_PB2 GPIO_ACTIVE_LOW>; }; 驱动编写 匹配设备节点 static const struct of_device_id of_gec_am2321_match[] = { { .compatible = "gpio-am2321", .data = NULL}, //compatible 兼容属性名,需与设备树节点的属性一致 { /* NULL */}, }; static struct platform_driver gec3399_am2321_driver = { .probe = rk_am_probe, .remove = rk_am_remove, .driver = { .name ="gpio-am2321", .of_match_table = of_gec_am2321_match, //设备树设备匹配 } }; 文件探索 static int rk_am_probe(struct platform_device *pdev) { int ret; struct device_node *buz_node = pdev->dev.of_node; printk(KERN_INFO "%sn", __func__); printk(KERN_INFO"gpio-am2321 math succeen"); ret = misc_register(&gec3399_am_misc); //注册字符设备 if(ret < 0){ printk(KERN_INFO"misc register errorn"); goto err_misc_register; } gpio_am = of_get_named_gpio(buz_node,"gpio-am2321", 0); //从设备树获取GPIO号 if (!gpio_is_valid(gpio_am)) { printk("gpio-am2321: %d is invalidn",gpio_am); ret = -ENODEV; goto err_get_gpio; } printk(KERN_INFO"gpio-am2321 = %dn",gpio_am); gpio_free(gpio_am); ret = gpio_request(gpio_am,"ak8963c_DYDR"); //申请gpio_am引脚为GPIO模式 if(ret < 0){ printk("gpio_request gpio = ak8963c_DYDR errorn"); goto err_get_gpio; } ret = gpio_direction_output(gpio_am,0); //初始划蜂鸣器为关闭状态 if(ret < 0){ printk("gpio direction input gpio = ak8963c_DYDR errorn"); goto err_gpio_direction; } printk( KERN_ALERT "am2321 dirve install succeen"); return 0; err_gpio_direction: gpio_free(gpio_am); err_get_gpio: misc_deregister(&gec3399_am_misc); err_misc_register: return ret; } 杂项设备 static struct miscdevice gec3399_am_misc = { .minor = MISC_DYNAMIC_MINOR, .fops = &gec3399_am_fops, .name = "am2321_drv", }; //混杂设备结构体定义和初始化 文件操作集 static const struct file_operations gec3399_am_fops = { .owner = THIS_MODULE, .read = am2321_read, .release = gec3399_am_release, }; //文件操作集结构体 读温湿度接口 static ssize_t am2321_read (struct file *file, char __user *buffer, size_t size, loff_t *offset) { int ret; unsigned long flags; unsigned short verify_sum = 0; //int i; debug("<0>""enter am2321_read functionnn"); debug("<0>""am2321_PIN level = %dn",read_pin_level()); /* 因为am2321的时序要求很高,所以在读温湿度的时候要让代码进入临界区,防止内核调度和抢占 */ local_irq_save(flags); ret = am2321_start_signal(); if(ret ==1) //如果收到应答 am2321_read_data(); else return -1; local_irq_restore(flags); debug("<0>""%x %x %x %x %xn",data_buf[0],data_buf[1],data_buf[2],data_buf[3],data_buf[4]); verify_sum = data_buf[0]+data_buf[1]+data_buf[2]+data_buf[3]; if(verify_sum == data_buf[4]) { /* 将读取的温湿度数据拷贝到用户空间 */ ret = copy_to_user(buffer, data_buf, 4); if(ret < 0) { debug("<0>""copy to user errn"); return -EAGAIN; } } else{ printk("data is errorrn"); } return 0; } 开始信号 static bool am2321_start_signal(void) { int i = 0; set_pin_level(1); mdelay(50); //第一步:拉低10ms set_pin_level(0); mdelay(1); //第二步:拉高30us set_pin_level(1); udelay(30); //第三步:等待am2321主动拉低 while(read_pin_level()==1) { i++; udelay(1); if(i>500){ debug("<0>""wait pin for low level out time! %s %dn",__FUNCTION__,__LINE__); goto err0; } } //debug("<0>""(1)wait pin for low level success! i=%dn",i); i = 0; //第四步:等待am2321拉高,不超过85us while(read_pin_level()==0) { i++; udelay(1); if(i>90){ debug("<0>""wait pin for hight level out time! %s %dn",__FUNCTION__,__LINE__); goto err0; } } //debug("<0>""(2)wait pin for hight level success! i=%dn",i); i = 0; //第五步:等待am2321拉低,不超过85us while(read_pin_level()==1) { i++; udelay(1); if(i>500){ debug("<0>""wait pin for data input out time! %s %dn",__FUNCTION__,__LINE__); goto err0; } } //debug("<0>""(3)wait pin for data input success! i=%dn",i); return 1; err0: set_pin_level(1); return 0; } 温湿度数据读取一个byte字节 static bool am2321_read_byte(char *byte) { int time=0; int i = 0; for(i=0; i<8; i++) { *byte = *byte << 1; //udelay(30); time=0; //等待高电平,开始读取数据 while(read_pin_level()==0) { time++; udelay(1); if(time > 500) { debug("<0>""wait pin for hight level out time! %s %dn",__FUNCTION__,__LINE__); return 0; } } //如果超过了30us后还是高电平,就是逻辑高电平,稳妥采取55us后读取。 udelay(40); *byte |= read_pin_level(); //等待一次数据读取结束 time = 0; while(read_pin_level()==1) { time++; udelay(1); if(time > 500) { debug("<0>""wait pin for low level out time! %s %dn",__FUNCTION__,__LINE__); return 0; } } } return 1; } 上层测试代码 #include #include #include #include #include /* 程序的入口函数 */ int main(int argc, char *argv[]) { int fd; char buf[4]; /* 定义存放数据的数组 */ int length; float tem,hum; /* 以只读方式打开设备节点 */ fd = open("/dev/am2321_drv", O_RDONLY); if(fd < 0) { printf("open failed!n"); return -1; } while(1) { sleep(3); length = read(fd, buf, 4); /* 读取温湿度数据 */ /* 将数据从终端打印出来 * buf[0] 湿度高8位部分 * buf[1] 湿度低8位部分 * buf[2] 温度高8位部分 * buf[3] 温度低8位部分 */ hum = (float)((buf[0]<<8)|buf[1])/10; tem = (float)((buf[2]<<8)|buf[3])/10; printf("Temp: %xH ==> %.1f Humi: %xH ==> %.1fn", (buf[2]<<8)|buf[3],tem,(buf[0]<<8)|buf[1],hum); } /* 关闭DHT11设备节点 */ close(fd); return 0; } Makefile编写 obj-m += am2321.o KERNELDIR:=/file/RK3399Pro/rk3399pro_git_repo/kernel PWD:=$(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules test: aarch64-linux-gnu-gcc am2321_test.c -o am2321_test clean: rm -rf *.o *.order .*.cmd *.ko *.mod.c *.symvers *.tmp_versions 测试步骤 编译源码 在ubuntu中输入: make 得到驱动目标文件am2321.ko 输入: make test 得到测试目标文件:am2321_test 加载驱动 在开发板命令终端输入: insmod am2321.ko 执行测试程序 在开发板命令终端输入: chmod 777 am2321_test ./am2321_test 实验现象 读取温湿度数据 root@linaro-alip:~# ./test/am2321_test [ 686.323038] <0>enter am2321_read functionn [ 686.323482] <0>am2321_PIN level = 1 [ 686.379139] <0>1 b5 1 19 d0 Temp: 119H ==> 28.1 Humi: 1b5H ==> 43.7 |
||||
|
||||
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
rk1126实现BT601输入,输入不带IIC接口的驱动程序
1661 浏览 0 评论
1451 浏览 1 评论
2592 浏览 3 评论
RK3568 Android11让系统ntp校准时间生效,需要设置些什么
3279 浏览 1 评论
5323 浏览 2 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-24 10:21 , Processed in 0.688664 second(s), Total 72, Slave 56 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191