linux驱动系列学习之温湿度显示(十)

这篇具有很好参考价值的文章主要介绍了linux驱动系列学习之温湿度显示(十)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、引言

        本篇博文写的是一个最近做的小项目。具体的功能为:检测温湿度传感器(dht11)的数据并显示到oled上面,通过mqtt协议传输到onenet平台。本项目功能简单,只是将之前博文介绍的一些东西整合起来。

        具体使用的技术有:linux单总线驱动dht11、i2c框架控制oled、poll机制(驱动和应用)、内核定时器的使用、队列、mqtt协议。

        使用到的环境:imx6ull开发板(正点原子阿波罗开发板)、ubuntu18(已安装交叉环境)、dht11温湿度传感器、i2c接口的0.96寸oled、onenet平台。

二、Linux驱动

1. dht11驱动

        dht11是使用单总线协议控制的数字温湿度传感器。这里使用模拟IO的方式进行驱动dht11。

1)dht11时序(记图、联系监删)

imx6ull mqtt,linux驱动学习,linux,驱动开发

主机IO引脚拉低数据线,保持 t1(至少 18ms)时间,拉高数据线 t2(20~ 40us)时间,等待 DHT11 的响应。dht11 会拉低数据线并保持 t3(40~50us)时间,作为响应信号, dht11 拉高数据线,保持 t4(40 ~50us)时间后,开始输出数据。

dht11的时序比较简单。程序控制按照其时序编写即可。Linux驱动中使用udelay、mdelay作为微秒级、毫秒级延时。程序代码如下。

2)Linux驱动程序

        a)dht11驱动的结构体,后面的程序需要使用这个结构体创建设备、控制IO,这里记录下dht11使用的系统资源。

struct dht11_device{
	dev_t                dev_id;                   //设备号
	int                  major;                    //主设备号
	int                  minor;                    //次设备号
	struct cdev	         cdev;                     //字符设备
	struct class         *class;                   //类
	struct device        *device;                  //设备
	struct device_node   *device_node;             //设备节点
	int                  gpio;                     //数据引脚
	uint16_t             humidity,  temperature;   //检测到的温湿度数据
	int                  data_flag;                //数据更新标志位
	struct timer_list    timer;
};

struct dht11_device g_dht11_device;  

   b) dht11本身的单总线驱动程序

#define DHT11_DelayMs(t)  mdelay(t)
#define DHT11_DelayUs(t)  udelay(t)   

#define DHT11_PIN_HIGH  1
#define DHT11_PIN_LOW   0 

#define DHT11_IO_OUT(dht11)          gpio_direction_output(dht11->gpio, 1);
#define DHT11_IO_IN(dht11)           gpio_direction_input(dht11->gpio)
#define DHT11_WRITE(dht11,bit)       gpio_set_value(dht11->gpio, bit)
#define DHT11_READ(dht11)            gpio_get_value(dht11->gpio)

//设置引脚电平
void dht11_set_gpio(struct dht11_device* dht11,int value)
{
	if(value == DHT11_PIN_HIGH){
		gpio_direction_output(g_dht11_device.gpio, DHT11_PIN_HIGH);//gpio_direction_output(dht11->gpio, DHT11_PIN_HIGH);
	}else if(value == DHT11_PIN_LOW){
		gpio_direction_output(g_dht11_device.gpio, DHT11_PIN_LOW);//gpio_direction_output(dht11->gpio, DHT11_PIN_LOW);
	}
	
}



//等待响应
static int dht11_wait_for_ready(struct dht11_device *dht)
{   
    int timeout;

    timeout = 400;
    while (DHT11_READ(dht) && timeout)      // 等待低电平到来 
    {
        udelay(1);
        --timeout;
    }
    if (!timeout) 
    {
        printk("timeout %d\n", __LINE__);
        return -1;    // 超时 
    }

    timeout = 1000;
    while (!DHT11_READ(dht) && timeout)      // 等待高电平到来  
    {
        udelay(1);
        --timeout;
    }
    if (!timeout) 
    {
        printk("timeout %d\n", __LINE__);
        return -1;    // 超时 
    }

    timeout = 1000;
    while (DHT11_READ(dht) && timeout)  // 等待高电平结束
    {
        udelay(1);
        --timeout;
    }
    if (!timeout) 
    {
        printk("timeout %d\n", __LINE__);
        return -1;    // 超时 
    }

    return 0;
}

//开始信号
static int dht11_start(struct dht11_device *dht)
{
    DHT11_IO_OUT(dht);
    DHT11_WRITE(dht,0);
    mdelay(20);
    DHT11_WRITE(dht,1);
    udelay(30);
    DHT11_IO_IN(dht);          // 设置为输入 
    udelay(2);
   
    if (dht11_wait_for_ready(dht)) return -1;
    return 0;
}

//读取数据
static int dht11_read_byte(struct dht11_device *dht,unsigned char *byte)
{
    unsigned char i;
    unsigned char bit = 0;
    unsigned char data = 0;
    int timeout = 0;   
    
    for (i = 0; i < 8; i++)
    {
        timeout = 1000;  
        while (DHT11_READ(dht) && timeout)   // 等待变为低电平 
        {
            udelay(1);
            --timeout;
        }
        if (!timeout) 
        {
            printk("timeout %d\n", __LINE__);         
            return -1;           // 超时 
        }

        timeout = 1000;
        while (!DHT11_READ(dht) && timeout)    // 等待变为高电平 
        {
            udelay(1);
            --timeout;
        }
        if (!timeout) 
        {
            printk("timeout %d\n", __LINE__);
            return -1;           // 超时 
        }
        udelay(40);
        
        bit = DHT11_READ(dht);

        data <<= 1;            
        if (bit) 
        {
            data |= 0x01;

        }
        // data <<= 1;          // 导致错误的原因 : 移位要放前面,不能放在这里,若放在后面一旦获取最后一个位就会多移动一位导致数据不对 
    }

    *byte = data;
    return 0;
}


//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
static int dht11_read_data(struct dht11_device* dht)
{        
     unsigned  char data[5] = {0};
	int i = 0,ret = 0;
    // 启动信号 
    if (dht11_start(dht) != 0)
    {
        printk("dht11 start failed\n");
        ret = -EFAULT;
    }

    // 读出5字节数据
    for (i = 0; i < 5; i++)    
    {
        if (dht11_read_byte(dht,&data[i]))
        {
            printk("read data err\n");
            ret = -EAGAIN;
        }
    }
	if (data[4] != (data[0]+data[1]+data[2]+data[3]))
    {
        printk("check data failed\n");
        ret = -EAGAIN;
    }
	dht->humidity = data[0];
    dht->temperature = data[2];
			
	return 0;
}

 c)与Linux驱动框架有关代码

static int __init dht11_init(void)
{
	int ret = 0;
	uint16_t humidity,temperature;

	// 1、获取设备节点:gpioled 

	g_dht11_device.device_node = of_find_node_by_path("/dht11");
	if(g_dht11_device.device_node == NULL) {
		printk("dht11 node not find!\r\n");
		return -EINVAL;
	} else {
		printk("dht11 node find!\r\n");
	}

	// 2、 获取设备树中的gpio属性,得到LED所使用的LED编号 
	g_dht11_device.gpio = of_get_named_gpio(g_dht11_device.device_node, "dht11-gpio", 0);
	if(g_dht11_device.gpio < 0) {
		printk("can't get dht11 gpio");
		return -EINVAL;
	}
	printk("dht11 gpio num = %d\r\n", g_dht11_device.gpio);

	// 3、设置GPIO1_IO03为输出,并且输出高电平
	gpio_request(g_dht11_device.gpio, "dht11_gpio");	// 请求IO 
	printk("dht11 gpio : %d\n",g_dht11_device.gpio);
	//gpio_direction_input(g_dht11_device.gpio);	// 设置为输入 
	ret = gpio_direction_output(g_dht11_device.gpio, 1);
	if(ret < 0) {
		printk("can't set gpio!\r\n");
	}

	// 注册字符设备驱动 
	// 4、创建设备号 
	if (g_dht11_device.major) {		//  定义了设备号 
		g_dht11_device.dev_id = MKDEV(g_dht11_device.major, 0);
		register_chrdev_region(g_dht11_device.dev_id, 1, DHT11_NAME);
	} else {						// 没有定义设备号 
		alloc_chrdev_region(&g_dht11_device.dev_id, 0, 1, DHT11_NAME);	// 申请设备号 
		g_dht11_device.major = MAJOR(g_dht11_device.dev_id);	// 获取分配号的主设备号
		g_dht11_device.minor = MINOR(g_dht11_device.dev_id);	// 获取分配号的次设备号
	}
	printk("gpioled major=%d,minor=%d\r\n",g_dht11_device.major, g_dht11_device.minor);	
	
	// 5、初始化cdev、添加一个cdev
	g_dht11_device.cdev.owner = THIS_MODULE;
	cdev_init(&g_dht11_device.cdev, &dht11_fops);
	cdev_add(&g_dht11_device.cdev, g_dht11_device.dev_id, 1);

	// 6、创建类 
	g_dht11_device.class = class_create(THIS_MODULE, DHT11_NAME);
	if (IS_ERR(g_dht11_device.class)) {
		return PTR_ERR(g_dht11_device.class);
	}

	// 7、创建设备
	g_dht11_device.device = device_create(g_dht11_device.class, NULL, g_dht11_device.dev_id, NULL, DHT11_NAME);
	if (IS_ERR(g_dht11_device.device)) {
		return PTR_ERR(g_dht11_device.device);
	}
	
	// 8、初始化定时器
	init_timer(&g_dht11_device.timer);
	g_dht11_device.timer.function = timer_func;
	g_dht11_device.timer.data = (volatile unsigned long)(&g_dht11_device);
	g_dht11_device.timer.expires = jiffies + msecs_to_jiffies(1000);//设定超时时间,1000代表1秒
	add_timer(&g_dht11_device.timer);//添加定时器,定时器开始生效	
    
    //仅用于驱动测试
	dht11_read_data(&g_dht11_device);	
	printk("humidity: %d   temperature: %d	 \n",g_dht11_device.humidity,g_dht11_device.temperature);
	
	return 0;
}


static void __exit dht11_exit(void)
{

	del_timer(&g_dht11_device.timer);  //删除定时器

	gpio_free(g_dht11_device.gpio);
	
	// 注销字符设备驱动 
	cdev_del(&g_dht11_device.cdev);//	删除cdev 
	unregister_chrdev_region(g_dht11_device.dev_id, 1); // 注销设备号 

	device_destroy(g_dht11_device.class, g_dht11_device.dev_id);
	class_destroy(g_dht11_device.class);

}



module_init(dht11_init);
module_exit(dht11_exit);
MODULE_LICENSE("GPL");

d)poll相关程序

        dht11使用了poll机制,这里用定时器每隔一定时间读取dht11的数据,将其保存下来,并通过poll函数通知应用程序。相关代码如下。

DECLARE_WAIT_QUEUE_HEAD(dht11_poll_queue);  //定义一个队列

//定时器回调函数,每一秒执行一次
static void timer_func(unsigned long arg)
{
	struct dht11_device *dht = (struct dht11_device *)arg;
	dht11_read_data(dht);    //每秒更新一次传感器数据
	dht->timer.function = timer_func;
	dht->timer.expires = jiffies + msecs_to_jiffies(1000);//设定超时时间,1000代表1秒
	add_timer(&(dht->timer));//添加定时器,定时器开始生效	
	//通知poll,数据可以读取
	dht->data_flag= 1;
	//printk("humidity: %d   temperature: %d	 \n",dht->humidity,dht->temperature);
		
}

static unsigned int dht11_poll (struct file * fp, poll_table * wait)
{
	unsigned int mask = 0;
	poll_wait(fp,&dht11_poll_queue, wait);
	if(g_dht11_device.data_flag == 1){  
		g_dht11_device.data_flag = 0;
		mask |= POLLOUT;	
	}
	return mask;
}

static ssize_t dht11_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	int err = 0;
	struct dht11_device *dht = filp->private_data;
	uint16_t data[] = { dht->humidity, dht->temperature };

	err = copy_to_user(buf, data, sizeof(data));
	return err;

}

// 设备操作函数 
static const struct file_operations dht11_fops = {
	.owner = THIS_MODULE,
	.open = dht11_open,
	.read = dht11_read,
	.release = 	dht11_release,
	.poll      = dht11_poll,
};

        应用层使用poll机制,等待dht11能够读取。使用read系统调用读取dht11的数据。

imx6ull mqtt,linux驱动学习,linux,驱动开发

        insmod进内核之后,显示的结果。

2. oled驱动

i2c接口的0.96寸oled在之前的博文里面已经讲解过。具体请参考博文:linux驱动系列学习之i2c子系统(四)

        这里面想说下,目前手里面只有i2c接口的oled,测试了一下写的驱动,刷新一帧挺慢的,后面考虑换成spi接口的oled,加上缓存区处理,应该能将显示效果提高不少。

三、应用

1.控制dht11

        这里给出dht11读取线程代码,只将其中一部分写出。本次poll函数只有一个dht11设备需要等待操作,这里给出5个pollfd,演示下poll等待多个文件可操作。

char* file_path = "/dev/htq-dht11";
int dht11_thread(void* p)
{

	uint16_t data[2] = { 0 };
	struct pollfd fds[5];
	int rc = 0;
	int i = 0;
	int fd = open(file_path, O_RDWR);
	printf("fd: %d\n",fd);
	fds[0].fd = fd;
	fds[0].events = POLLOUT;
	while(1){
		rc = poll(fds, 5, 3 * 1000);
		printf("rc: %d\n",rc);
		for(i = 0;i < 5;i++){
			if (fds[i].revents == POLLOUT)   //有数据可以读取
			{
				printf("i: %d  revents: %d\n",i,fds[i].revents);
				read(fds[i].fd,data,sizeof(data));
				printf("humidity: %d   temperature: %d	 \n",data[0],data[1]);
			}
		}
		
		sleep(1);
		
	}
}

2.oled显示

        这里,使用ioctl控制oled显示数据到某个位置。等待读取dht11数据,并将其显示出来。

#define OLED_PATH "/dev/oled_htq"
#define TEMP_HUMI_PATH "/dev/htq-dht11"

#define POLL_CNT 1
int show_temperature_humidity(int _oled_fd, int x, int y, double temperature, double humidity);
int oled_fd = 0, temp_humi_fd = 0;

int oled_thread(void* p)
{    
    uint16_t data[2] = { 0 };
	struct pollfd fds[POLL_CNT];  
    double temperature,  humidity;
    int i = 0,rc = 0;
    
    oled_fd = open(OLED_PATH, O_RDWR);
    if (oled_fd < 0) {
        printf("open %s", OLED_PATH);
        fflush(stdout);
        perror(" ");
        return 0;
    }
    temp_humi_fd = open(TEMP_HUMI_PATH, O_RDWR);
    if (temp_humi_fd < 0) {
        printf("open %s", TEMP_HUMI_PATH);
        fflush(stdout);
        perror(" ");
        return 0;
    }
    
    printf("oled_fd: %d\n",oled_fd);
	printf("temp_humi_fd: %d\n",temp_humi_fd);
	fds[0].fd = temp_humi_fd;
	fds[0].events = POLLOUT;
	while(1){
		rc = poll(fds, POLL_CNT, 3 * 1000);
		for(i = 0;i < POLL_CNT;i++){
			if (fds[i].revents == POLLOUT)   //有数据可以读取
			{
				//printf("i: %d  revents: %d\n",i,fds[i].revents);
				read(fds[i].fd,data,sizeof(data));
				//printf("humidity: %0.2f   temperature: %0.2f	 \n",data[0],data[1]);
                humidity = data[0];
                temperature = data[1];
                show_temperature_humidity(oled_fd,0,0,temperature,humidity);
			}
		}
		
		sleep(1);
		
	}

    close(oled_fd);
    close(temp_humi_fd);
    return 0;	
}


int show_temperature_humidity(int _oled_fd, int x, int y, double temperature, double humidity)
{
   
    uint8_t cur_x = 0, cur_y = 0;
    uint32_t data =  0; 
    char buffer[168] =  { 0 };  //最多显示168个字符
    if(_oled_fd <= 0) return -1;
    if(x > 126 || y > 6)   return -2;
    cur_x = x;
    cur_y = y;
    data = cur_y;
    data <<= 8;
    data |=  cur_x;
    ioctl(_oled_fd,13,data);   //13是自定的设置oled的显示(x,y)

    memset(buffer,0,sizeof(buffer));  
    sprintf(buffer,"temperature: %0.2f",temperature);  
    write(_oled_fd,buffer,strlen(buffer));


    cur_x = x;
    cur_y = y + 1;
    data = cur_y;
    data <<= 8;
    data |=  cur_x;
    ioctl(_oled_fd,13,data); 

    memset(buffer,0,sizeof(buffer));  
    sprintf(buffer,"humidity: %0.2f",humidity);  
    write(_oled_fd,buffer,strlen(buffer));
    return 0;
}

        运行代码,在oled上面显示温湿度数据。

imx6ull mqtt,linux驱动学习,linux,驱动开发

3.mqtt传输

         mqtt协议应用十分广泛,本次使用onenet平台演示功能。具体怎么在onenet上搭建mqtt环境,请参考其他博主的文章。本博文使用的多协议接入这个。使用的是onenet自身提供的MQTT协议API传输数据,在demo里面,有三个变量需要根据自己搭建的环境进行修改。分别是

char* prjid = "XX1154"; //project_id

char* auth_info = "htqmqtt2"; //authoriz info

char* devid = "XX9174017";  //device_id

        这三个变量唯一确定一个设备。之后使用响应的API进行传输数据,这里,将主要的代码放下。

int mqtt_thread(void *p)  
{ 
    int ret = 0;
    int err, flags;
    int keep_alive = 1200;
    struct MqttSampleContext smpctx[1],*ctx = smpctx;
    ctx->host   = "183.230.40.39";
    ctx->port   = 6002;

    ret = MqttSample_Init(smpctx);
    printf("MqttSample_Init ret: %d\n",ret); 

    MqttBuffer_Init(ctx->mqttbuf);



    ctx->mqttfd = MqttSample_CreateTcpConnect(ctx->host, ctx->port);
    if(ctx->mqttfd < 0) {
        return -1;
    }
    ctx->mqttctx->read_func_arg = (void*)(size_t)ctx->mqttfd;
    ctx->mqttctx->writev_func_arg = (void*)(size_t)ctx->mqttfd;



    err = Mqtt_PackConnectPkt(ctx->mqttbuf, keep_alive, devid, 1,
                              NULL, NULL, 0,
                              MQTT_QOS_LEVEL0, 0, prjid,
                              auth_info, strlen(auth_info));
    printf("Mqtt_PackConnectPkt ret: %d\n",err); 

    ret = Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0); //发送数据包,将数据发送到onennet
    printf("Mqtt_SendPkt ret: %d\n",ret); 

    ret = Mqtt_RecvPkt(ctx->mqttctx);
    printf("Mqtt_RecvPkt ret: %d\n",ret); 


  
    uint32_t size = 0
    int retain = 0;
    int own = 1;
    char send_buffer[1024];
    double temperature = 21.2, humidity = 61.2;
    int i = 0;
    while(1){
        MqttBuffer_Init(ctx->mqttbuf);
        memset(send_buffer,0,sizeof(send_buffer));  

        sprintf(send_buffer,"[{\"temperature\":%0.2f,\"humidity\":%0.2f}]", temperature, humidity);



        temperature += 0.1;
        humidity += 0.2;
        size = strlen(send_buffer);
        ret = Mqtt_PackDataPointByString(ctx->mqttbuf, g_pkt_id++, 0, kTypeSimpleJsonWithoutTime, send_buffer, size, MQTT_QOS_LEVEL0, retain, own);
        printf("Mqtt_RecvPkt ret: %d\n",ret);

        ret =  Mqtt_SendPkt(ctx->mqttctx, ctx->mqttbuf, 0);
        printf("Mqtt_RecvPkt ret: %d\n",ret);
        sleep(1);
    }        



    MqttBuffer_Destroy(smpctx->mqttbuf);
    Mqtt_DestroyContext(smpctx->mqttctx);

    if(smpctx->epfd >= 0) {
        close(smpctx->epfd);
        smpctx->epfd = -1;
    }

    if(smpctx->mqttfd >= 0) {
        close(smpctx->mqttfd);
        smpctx->mqttfd = -1;
    }
 

    return 0;
}

imx6ull mqtt,linux驱动学习,linux,驱动开发

 mqtt传输到onenet平台上显示的相应结果。发送的数据是随便发送的,这个是之前进行测试。

四、总结

        本项目做的功能十分简单,只是把之前学的做个简单的总结。里面也有许多不足的地方,如oled显示部分,应该使用GRAM现存,使用定时器每隔一段时间刷新一次,这样显示的效果会更好。在应用层应该使用QT开发界面。下面有时间的话,会进行一定的修改文章来源地址https://www.toymoban.com/news/detail-566350.html

到了这里,关于linux驱动系列学习之温湿度显示(十)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • linux添加sht3x温湿度传感器驱动记录

           最近拿到一块imx6ull板子,上面有一颗温湿度传感器sht30,需要读取其数值。本人能力有限,自己写驱动还有一点困难,好在 linux内核里自带了很多器件的驱动,只需要找到相关的驱动文件根据要求修改一下设备树、添加进内核里编译就可以。         目前新版本的l

    2024年02月10日
    浏览(29)
  • IIC学习之SHT30温湿度传感器(基于STM32)

    附上SHT30资料和逻辑分析仪源文件,点击下载 关于IIC的介绍网上已经非常详尽,这里只说重点: 双线(SDA,SCL),半双工 采用主从结构,支持一主多从,通过地址寻址,每个I2C设备都有唯一的7位或10位地址,还有1bit选择读写(0为写,1为读) 速率较低,I2C总线支持多种通信

    2024年02月01日
    浏览(38)
  • 数据可视化----网页显示温湿度

    将ESP8266上报到云端的温湿度数据,在网页上显示出来,使得我们可以随时随地查看办公室的实时温湿度 @:温湿度数据上报到【物接入】,通过【规则引擎】将温湿度数据送往【数据库】/【云主机】 之后,我们在主机上进行【前端+后端】开发,从而在网页上显示温湿度,

    2024年01月18日
    浏览(42)
  • STM32日历读取与温湿度显示

    STM32的 RTC 外设(Real Time Clock),实质是一个掉电后还继续运行的定时器。 掉电: 读取STM32F103C8T6 内部的时钟(年月日时分秒),日历(星期x),1秒周期,通过串口输出到PC上位机 1、初始化 RTC 外设; 2、设置时间以及添加配置标志; 3、获取当前时间; 1、定义时间结构体,包含

    2024年02月20日
    浏览(27)
  • 十一、DHT11 温湿度检测(OLED显示)

    见博客:stm32f103c8t6新建固件库模板(可自取) 固件库模板 MDK5开发环境 stm32参考手册 利用固件库模板点灯工程(下面第三行,手动狗头) OLED模块资料 DHT11数据手册 利用固件库模板点灯工程(下面第三行,手动狗头) CH340 USB→TTL模块 实验程序已经发布到百度网盘,本文末有

    2024年02月01日
    浏览(29)
  • stm32项目之DHT11温湿度显示(LCD1602)

    掌握LCD1602的使用 掌握DHT11的原理及使用 看懂LCD1602和DHT11时序图 看懂DHT11的原理 掌握LCD1602的显示 编写程序用LCD1602显示温湿度 DHT11部分: DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次 通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当

    2024年02月02日
    浏览(45)
  • Clion开发Stm32之温湿度传感器(DHT11)驱动编写

    涵盖之前文章: Clion开发STM32之HAL库GPIO宏定义封装(最新版) Clion开发stm32之微妙延迟(采用nop指令实现) Clion开发STM32之日志模块(参考RT-Thread) 头文件 源文件

    2024年02月15日
    浏览(30)
  • 第七章 OLED+DHT11+STM32动态显示温湿度

            上一章给大家介绍了OLED显示模块的使用,但上一章我们在OLED上显示的是静态的,不会变动的,所以这一章我结合第一章介绍的DHT11温湿度模块,实现温湿度数值在OLED显示模块上进行动态显示,其实也是非常简单。         首先打开第一章提供的DHT11代码工程文件和

    2024年01月16日
    浏览(32)
  • 使用STM32 在实现温湿度LCD显示并蓝牙透传

    通过温湿度传感器将值传到LCD1602,并实时通过蓝牙透传到手机。 LCD1602 是一种工业字符型液晶,能够同时显示16x02即32字符 (16列两行) DHT11  DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。 HC-01 蓝牙模块。 关于以上这三个模块的使用和详细介绍

    2024年02月17日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包