基于gec6818的環境監測系統設計

一、設計要求

  1. 將環境中溫濕度數值、環境的光照強度和煙霧的信息獲取到開發板,顯示在圖形界面上。
  2. 當溫度值高于閾值時,溫度指示燈變紅、蜂鳴器告警并且啟動直流電機正轉降溫;當濕度值高于閾值時,濕度指示燈變紅、蜂鳴器告警并且繼電器吸合接通除濕電路;當光照度大于閾值時,光照度指示燈變紅、蜂鳴器告警并且步進電機正轉關閉窗簾;當檢測到煙霧時,煙霧指示燈變紅、蜂鳴器告警;報警聲音的頻率可通過圖形界面進行設置。
  3. 溫濕度告警閾值、光照度告警閾值可以通過界面進行設置并且保存到配置文件,系統重新上電后,讀取配置文件的配置參數。
  4. 實驗箱可通過UDP協議將溫濕度、照度和煙霧數據傳輸到x86上的ubuntu上的圖形界面顯示,并且實驗箱和x86上的ubuntu的可以通過圖形界面進行文本信息的交流。
  5. 修改啟動腳本,使系統上電后自動運行本次實驗設計的圖形界面。

二、實驗原理

????????該嵌入式 Linux 環境監測系統采用模塊化設計,主要包含硬件采集、核心控制、設備執行、軟件交互四大模塊。

????????硬件采集模塊集成溫濕度傳感器、光敏電阻與煙霧傳感器,負責實時感知環境參數變化,為系統提供原始數據。

????????核心控制模塊以粵嵌GEC6818開發板為載體,搭載Linux操作系統,通過編寫設備驅動程序,實現對傳感器數據的讀取解析,同時運行QT應用程序進行數據處理與邏輯判斷。

????????設備執行模塊由繼電器、步進電機蜂鳴器和直流電機組成,根據核心控制模塊的指令,繼電器在光照強度高于設定的閾值時吸合,觸點閉合,電路通斷狀態改變當光敏元件上的光照強度降低到一定閾值以下時,光敏元件的導通電流或電阻值恢復原狀,繼電器也會恢復到原來的狀態步進電機可在檢測光照強度高于閾值時啟動,可以與窗簾聯動,通過驅動拉開窗簾,使其參數值降低;蜂鳴器在環境參數超設定閾值時,觸發聲光報警直流電機在檢測到煙霧和環境溫度高于閾值時啟動風扇,使其參數值降低;

????????軟件交互模塊基于QT框架開發可視化界面,不僅能實時展示環境數據,還支持閾值參數設置,便于用戶遠程監控與管理系統,各模塊協同工作實現環境監測與智能調控功能。

三、系統模塊分析

3.1.1 環境監測模塊

3.1.1.1 ?溫濕度監測模塊

????????溫濕度監測中,采用了DHT11溫濕度傳感器。VDD_IO為傳感器供電,電容C67濾波保證電壓穩定。R124作為上拉電阻,使數據傳輸引腳在空閑時保持高電平狀態,R125則將傳感器數據引腳連接至XEINT24_B引腳,以便與外部控制設備通信。工作時,微控制器先發送起始信號,傳感器響應后,通過單總線傳輸40位包含溫濕度整數、小數部分及校驗和的數據,微控制器接收并校驗數據,若準確無誤,便對溫濕度數據進行后續處理與應用,如顯示或依據數據觸發相關控制動作。

溫度檢測的驅動代碼如下:
//頭文件來源于linux內核源碼
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/gpio.h>		//函數聲明
#include "cfg_type.h" 	 	//端口宏定義
#include <linux/ioport.h>	//IO相關
#include <linux/delay.h> 	//延時函數
#include <linux/time.h>
#include "led_cmd.h"
//1.定義一個字符設備
static struct cdev dht11_cdev;
static unsigned int dht11_major = 0; //主設備號;0--動態;>0--靜態
static unsigned int dht11_minor = 0; //次設備號
static dev_t dht11_dev_num; 		   //設備號
static struct class *dht11_class;
static struct device *dht11_device;
#define DHT_DATA (??????)
static int gec6818_dht11_open(struct inode *inode, struct file *filp)
{gpio_set_value(DHT_DATA, 1);printk("dht11 driver is openning\n");	//應用程序打開驅動文件時打印return 0;
}static int gec6818_dht11_release(struct inode *inode, struct file *filp)
{gpio_set_value(DHT_DATA, 1);printk("dht11 driver is closing\n");//應用程序關閉驅動文件時打印return 0;
}
static unsigned char get_byte(void)
{int i=0, k=0;int ret_data = 0;for(k=0; k<8; k++){i=0;//復位計數值while(!gpio_get_value(DHT_DATA))//等待總線拉高跳出{i++;udelay(1);if(i > 120){printk("DTH11  high timeout error\n");break;}}udelay(22);ret_data <<= 1;//逐漸將數據移到最高位if(gpio_get_value(DHT_DATA))ret_data |= 0x01;//接收最高位放在第一位 1 只取1,0初始化已經填充i=0;//復位計數值while(gpio_get_value(DHT_DATA))//等待總線拉低跳出{i++;udelay(1);if(i > 200){printk("DTH11  low level timeout error\n");break;}}		}return ret_data;
}static long gec6818_dht11_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{int ret, i=0 ; unsigned long flags;//中斷保存unsigned char dth11_data[5]={0};//數據組unsigned char checksum = 0;//校驗和if(cmd == GEC6818_GET_DHTDATA){local_irq_save(flags);//關閉中斷ret =gpio_direction_output(DHT_DATA, 0);//設置輸出if(ret != 0)printk("gpio_direction_output DHT_DATA error\n");gpio_set_value(DHT_DATA, 0);//主機拉低18msmsleep(20);ret =gpio_direction_input(DHT_DATA);//設置輸入 if(ret != 0){printk("gpio_direction_input DHT_DATA error\n");local_irq_restore(flags); //恢復中斷return ret;}udelay(10);if(gpio_get_value(DHT_DATA))//如果響應會拉低總線電平{printk("DTH11  timeout error\n");local_irq_restore(flags); //恢復中斷return -EAGAIN;//超時重試}i = 0;while(!gpio_get_value(DHT_DATA))//等待總線拉高跳出{i++;udelay(1);if(i > 160){printk("DTH11  high timeout error\n");local_irq_restore(flags);//恢復中斷 return -EAGAIN;//超時重試}}i = 0;while(gpio_get_value(DHT_DATA))//等待總線拉低跳出{i++;udelay(1);if(i > 160){printk("DTH11  low level timeout error\n");local_irq_restore(flags); //恢復中斷return -EAGAIN;//超時重試}}for(i = 0; i<5; i++)dth11_data[i] = get_byte();		
checksum = dth11_data[0] + dth11_data[1] + dth11_data[2] + dth11_data[3];//統計校驗和if(checksum != dth11_data[4])//判斷校驗和{printk("DTH11  checksum error\n");return -EAGAIN;	//超時重試}local_irq_restore(flags);//恢復中斷}elsereturn -ENOIOCTLCMD;//無效命令	printk("th_data = %hhd  temp_data = %hhd\n", dth11_data[0], dth11_data[2]);ret = copy_to_user(((unsigned char *)arg)+2,&dth11_data[0],2);		if( ret != 0 )return -EFAULT;ret = copy_to_user((unsigned char *)arg,&dth11_data[2],2)if( ret != 0 )return -EFAULT;return 0;
}static const struct file_operations gec6818_dht11_fops = {.owner = THIS_MODULE,.unlocked_ioctl = gec6818_dht11_ioctl,.open = gec6818_dht11_open,.release = gec6818_dht11_release,
};//驅動的安裝函數
static int __init gec6818_dht11_init(void)
{int ret;//2.申請設備號(靜態注冊 or 動態分配)if(dht11_major == 0){ret=alloc_chrdev_region(&dht11_dev_num,dht11_minor,1,"dht11_device");	}else{dht11_dev_num = MKDEV(dht11_major,dht11_minor);ret = register_chrdev_region(dht11_dev_num, 1, "dht11_device");}if(ret < 0){printk("can not get dht11 device number\n");return ret; //返回錯誤的原因}//4.初始化cdevcdev_init(&dht11_cdev, &gec6818_dht11_fops);//5.將初始化好的cdev加入內核ret = cdev_add(&dht11_cdev, dht11_dev_num, 1);if(ret < 0){printk("cdev add error\n");goto cdev_add_err;}//6.創建classdht11_class = class_create(THIS_MODULE, "dht11_class");if(IS_ERR(dht11_class)){ret =PTR_ERR(dht11_class);printk("dht11 driver class create error\n");goto class_create_err;}	//7.創建devicedht11_device = device_create(dht11_class, NULL,//設備名稱dht11_dev_num, NULL, "dht11_dev");//dev/dht11_drvif(IS_ERR(dht11_device)){ret =PTR_ERR(dht11_device);printk("dht11 driver device create error\n");goto device_create_err;}if(gpio_request(DHT_DATA,"DHT_DATA") !=0)//申請物理內存區printk("gpio_request DHT_DATA error\n");		ret =gpio_direction_output(DHT_DATA, 1);//設置輸出if(ret != 0){printk("gpio_direction_output DHT_DATA error\n");gpio_free(DHT_DATA);goto device_create_err;}printk(KERN_INFO "gec6818_dht11_init\n");return 0;//出錯處理
device_create_err:class_destroy(dht11_class);
class_create_err:cdev_del(&dht11_cdev);
cdev_add_err:	unregister_chrdev_region(dht11_dev_num, 1);return ret;
}//驅動的卸載函數
static void __exit gec6818_dht11_exit(void)
{gpio_free(DHT_DATA);device_destroy(dht11_class, dht11_dev_num);class_destroy(dht11_class);cdev_del(&dht11_cdev);unregister_chrdev_region(dht11_dev_num, 1);printk(KERN_INFO "gec6818_dht11_exit\n");	
}module_init(gec6818_dht11_init);//入口函數
module_exit(gec6818_dht11_exit);//出口函數MODULE_AUTHOR("sugar@NNLG.com");
MODULE_DESCRIPTION("dht11 driver for GEC6818");
MODULE_LICENSE("GPL"); //符合GPL協議
MODULE_VERSION("V1.0");

?

3.1.1.2 ?光照強度監測模塊

????????光照強度監測中,采用了光照傳感器,光照傳感器CS1利用光電效應,其等效電阻隨光照強度變化而改變 。CS1與R117、R116組成分壓電路,光照強度改變會使R116兩端電壓變化,該模擬電壓信號經XadcAIN3引腳傳輸至ADC模塊 ,轉換為數字信號后被微控制器等處理單元接收,依據預設轉換關系換算出實際光照強度值,以此實現對光照強度的檢測。

光照強度監測的驅動代碼如下:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>#include <linux/io.h>
#include <linux/gpio.h>
#include <cfg_type.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>#define GEC6818_ADC_IN0	_IOR('A',  0, unsigned long)
#define GEC6818_ADC_IN1	_IOR('A',  1, unsigned long)
#define GEC6818_ADC_IN2	_IOR('A',  2, unsigned long) //光敏電阻
#define GEC6818_ADC_IN3	_IOR('A',  3, unsigned long) static void __iomem		*adc_base_va;		//adc的虛擬地址基址
static void __iomem		*adccon_va;		
static void __iomem		*adcdat_va;	
static void __iomem		*prescalercon_va;
static int  gec6818_adc_open (struct inode * inode, struct file *file)
{printk("gec6818_adc_open \n");return 0;
}
static int  gec6818_adc_release (struct inode * inode, struct file *file)
{printk("gec6818_adc_release \n");return 0;
}static long gec6818_adc_ioctl (struct file *filp, unsigned int cmd, unsigned long args)
{unsigned long adc_val=0,adc_vol=0; int rt=0;//adc通道選擇#define switch(cmd){case GEC6818_ADC_IN0:iowrite32(ioread32(adccon_va)&(~(7<<3)),adccon_va);break;case GEC6818_ADC_IN1:{iowrite32(ioread32(adccon_va)&(~(7<<3)),adccon_va);iowrite32(ioread32(adccon_va)|(1<<3),adccon_va);}break;		case GEC6818_ADC_IN2:{iowrite32(ioread32(adccon_va)&(~(7<<3)),adccon_va);iowrite32(ioread32(adccon_va)|(2<<3),adccon_va);}break;case GEC6818_ADC_IN3:{iowrite32(ioread32(adccon_va)&(~(7<<3)),adccon_va);iowrite32(ioread32(adccon_va)|(3<<3),adccon_va);}break;	default:printk("IOCTLCMD failed\n");return -ENOIOCTLCMD;}//將電源開啟iowrite32(ioread32(adccon_va)&(~(1<<2)),adccon_va);//預分頻值=199+1,ADC的工作頻率=200MHz/(199+1)=1MHziowrite32(ioread32(prescalercon_va)&(~(0x3FF<<0)),prescalercon_va);iowrite32(ioread32(prescalercon_va)|(199<<0),prescalercon_va);//預分頻值使能iowrite32(ioread32(prescalercon_va)|(1<<15),prescalercon_va);//ADC使能//iowrite32(ioread32(adccon_va)&(~(1<<0)),adccon_va);iowrite32(ioread32(adccon_va)|(1<<0),adccon_va);//等待AD轉換結束while(ioread32(adccon_va)&(1<<0));//讀取12bit數據adc_val = ioread32(adcdat_va)&0xFFF;//關閉CLKIN時鐘輸入iowrite32(ioread32(prescalercon_va)&(~(1<<15)),prescalercon_va);//關閉ADC電源iowrite32(ioread32(adccon_va)|(1<<2),adccon_va);//將AD轉換的結果值 換算為 電壓值adc_vol = adc_val*1800/4095;rt = copy_to_user((void *)args,&adc_vol,4);if(rt != 0)return -EFAULT;return 0;
}
static ssize_t gec6818_adc_read (struct file *file, char __user *buf, size_t len, loff_t * offs)
{return 0;
}static const struct file_operations gec6818_adc_fops = {.owner 			= THIS_MODULE,.unlocked_ioctl = gec6818_adc_ioctl,.open 			= gec6818_adc_open,.release 		= gec6818_adc_release,.read 			= gec6818_adc_read,
};static struct miscdevice gec6818_adc_miscdev = {.minor		= MISC_DYNAMIC_MINOR,	//MISC_DYNAMIC_MINOR,動態分配次設備號.name		= "adc_drv",		//設備名稱,/dev/adc_drv	.fops		= &gec6818_adc_fops,	//文件操作集
};
//入口函數
static int __init gec6818_adc_init(void)
{int rt=0;// struct resource *adc_res=NULL;//混雜設備的注冊rt = misc_register(&gec6818_adc_miscdev);if (rt) {printk("misc_register fail\n");return rt;}//IO內存動態映射,得到物理地址相應的虛擬地址adc_base_va = ioremap(0xC0053000,0x14);if(adc_base_va == NULL){printk("ioremap 0xC0053000,0x14 fail\n");goto fail_ioremap_adc;		}	//得到每個寄存器的虛擬地址adccon_va 		= adc_base_va+0x00;adcdat_va 		= adc_base_va+0x04;	prescalercon_va = adc_base_va+0x10;	printk("gec6818 adc init\n");return 0;fail_ioremap_adc:misc_deregister(&gec6818_adc_miscdev);return rt;
}
//出口函數
static void __exit gec6818_adc_exit(void)
{	iounmap(adc_base_va);misc_deregister(&gec6818_adc_miscdev);printk("gec6818 adc exit\n");
}
//驅動程序的入口:insmod led_drv.ko調用module_init,module_init又會去調用gec6818_adc_init。
module_init(gec6818_adc_init);//驅動程序的出口:rmsmod led_drv調用module_exit,module_exit又會去調用gec6818_adc_exit。
module_exit(gec6818_adc_exit)//模塊描述
MODULE_AUTHOR("sugar@NNLG");			    //作者信息
MODULE_DESCRIPTION("gec6818 adc driver");		//模塊功能說明
MODULE_LICENSE("GPL");							//許可證:驅動遵循GPL協議

3.1.1.3 ?煙霧濃度監測模塊

????????該煙霧檢測模塊原理圖中,采用了MQ-2煙霧傳感器,MQ-2煙霧傳感器利用氣敏特性,其電阻值會隨周圍煙霧濃度變化而改變。VDD_5V為電路供電R100與MQ-2組成分壓電路,煙霧濃度變化時,分壓值也隨之改變。該模擬信號經R101輸入到LM393電壓比較器與R99(可調電阻)設定的基準電壓對比,當煙霧濃度達到一定程度,比較器輸出電平翻轉,通過XEINT22_B引腳將信號傳輸給主控單元,同時D16發光二極管亮起,實現煙霧檢測與指示;C57、C60、C61等電容起到濾波作用,確保電路穩定工作。

煙霧濃度監測的驅動代碼如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <cfg_type.h>#define DEVICE_NAME		"gec_gas_drv"                  //設備名稱
//煙霧結構體
struct gas_desc {int gpio;int number;char *name;	struct timer_list timer;
};//煙霧設備的管腳,編號,名字
static struct gas_desc gas[] = {{ ?????, 0, "gas0" },
};//初始值
static volatile char gas_values[] = {'0'
};
//等待隊列
static DECLARE_WAIT_QUEUE_HEAD(gas_waitq);
static volatile int ev_press = 0;  //進入休眠的條件//煙霧的次數
static void gec6818_gas_timer(unsigned long _data)
{struct gas_desc *bdata = (struct gas_desc *)_data;int down;int number;unsigned tmp;tmp = gpio_get_value(bdata->gpio);/* active low */    //檢測到煙霧,比較器輸出低電平down = !tmp;//printk(KERN_DEBUG "KEY %d: %08x\n", bdata->number, down);number = bdata->number;//前后兩次狀態不一樣 才認為是檢測到一次煙霧if (down !=(gas_values[number] & 1)) {gas_values[number] = '0' + down;   // +'0' 將數字轉換為charev_press = 1;//將等待隊列中的進程變為可運行態,具體進程什么時候被執行,取決于調度程序;wake_up_interruptible(&gas_waitq);}
}
//煙霧中斷
static irqreturn_t gas_interrupt(int irq, void *dev_id)
{struct gas_desc *bdata = (struct gas_desc *)dev_id;mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(40));return IRQ_HANDLED;
}//打開設備
static int gec6818_gas_open(struct inode *inode, struct file *file)
{int irq;int i;int err = 0;//中斷申請for (i = 0; i < ARRAY_SIZE(gas); i++) {if (!gas[i].gpio)continue;gpio_free(gas[i].gpio);setup_timer(&gas[i].timer, gec6818_gas_timer,(unsigned long)&gas[i]);irq = gpio_to_irq(gas[i].gpio);   //IRQ_TYPE_EDGE_BOTH雙邊沿觸發err = request_irq(irq, gas_interrupt, IRQ_TYPE_EDGE_BOTH, gas[i].name, (void *)&gas[i]);if (err)break;}//出現錯誤,中斷釋放if (err) {i--;for (; i >= 0; i--) {if (!gas[i].gpio)continue;irq = gpio_to_irq(gas[i].gpio);disable_irq(irq);free_irq(irq, (void *)&gas[i]);del_timer_sync(&gas[i].timer);}return -EBUSY;}ev_press = 1;return 0;
}
//關閉中斷
static int gec6818_gas_close(struct inode *inode, struct file *file)
{int irq, i;for (i = 0; i < ARRAY_SIZE(gas); i++) {if (!gas[i].gpio)continue;irq = gpio_to_irq(gas[i].gpio);free_irq(irq, (void *)&gas[i]);del_timer_sync(&gas[i].timer);}return 0;
}
//煙霧數據讀取
static int gec6818_gas_read(struct file *filp, char __user *buff,size_t count, loff_t *offp)
{//printk("**********cin***************\n");unsigned long err;if (!ev_press) {if (filp->f_flags & O_NONBLOCK)return -EAGAIN;else   //當ev_press為非0時,立馬返回,不會休眠,當為0時,線程加入等待隊列鏈表中,然后線程進入休眠狀態。wait_event_interruptible(gad_waitq, ev_press); //進入}ev_press = 0;err = copy_to_user((void *)buff,(const void *)(&gas_values),min(siaeof(gas_values),count));//printk("**********cout***************\n");return err ? -EFAULT : min(sizeof(gas_values), count);
}
//煙霧頭部,Poll方法只是做一個登記 真正的阻塞發生在select.c 中的 do_select函數
static unsigned int gec6818_gas_poll( struct file *file,struct poll_table_struct *wait)
{unsigned int mask = 0;//把等待隊列添加到poll_tablepoll_wait(file, &gas_waitq, wait);if (ev_press)    //if (有數據可讀)mask |= POLLIN | POLLRDNORM; return mask;   //返回掩碼
}
//文件操作集
static struct file_operations dev_fops = {.owner		= THIS_MODULE,.open		= gec6818_gas_open,.release	= gec6818_gas_close, .read		= gec6818_gas_read,.poll		= gec6818_gas_poll,
};
//雜項設備
static struct miscdevice misc = {.minor		= MISC_DYNAMIC_MINOR,.name		= DEVICE_NAME,.fops		= &dev_fops,
};
//驅動的初始化函數--->從內核中申請資源(內核、中斷、設備號、鎖....)
static int __init button_dev_init(void)
{int ret;ret = misc_deregister(&misc);printk(DEVICE_NAME"\tinitialized\n");return ret;
}
//驅動退出函數 --->將申請的資源還給內核
static void __exit button_dev_exit(void)
{misc_deregister(&misc);
}
module_init(button_dev_init);                       //驅動的入口函數會調用一個用戶的初始化函數
module_exit(button_dev_exit);				        //驅動的出口函數會調用一個用戶的退出函數//驅動的描述信息: #modinfo  *.ko , 驅動的描述信息并不是必需的。
MODULE_AUTHOR("sugar@nnlg");                         //驅動的作者
MODULE_DESCRIPTION("Gas of driver");                //驅動的描述
MODULE_LICENSE("GPL");                              //遵循的協議

?

3.1.2 智能調控模塊

3.1.2.1 溫度調控? ? ? ?

????????溫度調控中,由直流電機驅動風扇降低環境。LG9110是直流電機驅動芯片,由VDD_5V供電。微控制器通過XEINT20_B和XEINT21_B引腳向LG9110的IA和IB引腳輸入控制信號,不同的電平組合能夠控制芯片內部的電路通斷,進而控制輸出引腳OA和OB的電平狀態,以此實現對直流電機正轉、反轉、停止等狀態的控制。當檢測到環境溫度過高,微控制器輸出相應信號使電機正轉,帶動風扇運轉,加速空氣流動來降低溫度;C62和C63電容組成濾波電路,能穩定電源電壓,減少電源波動對電機驅動芯片和電機的影響,確保電機穩定運行。

直流電機驅動代碼如下所示:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <mach/platform.h>
#include <asm/gpio.h>#define DEVICE_NAME      "dc_motor"            //設備名字      
//電機管腳
static int motor_gpios[] = {(????),//電機管腳,需要自己修改(????),//電機管腳,需要自己修改
};#define MOTOR_NUM		ARRAY_SIZE(motor_gpios) //電機的數量
//電機初始化
static void motor_init(void)
{gpio_set_value(motor_gpios[0], 0);gpio_set_value(motor_gpios[1], 0);
}
//電機正傳
static void motor_foreward(void)
{gpio_set_value(motor_gpios[0],1);gpio_set_value(motor_gpios[1],0);
}//電機反轉
static void motor_rollback(void)
{gpio_set_value(motor_gpios[1],1);gpio_set_value(motor_gpios[0],0);
}
//電機設備打開
static int gec6818_motor_open(struct inode *inode, struct file *filp)
{printk(DEVICE_NAME ":open\n");motor_init();return 0;
}
//電機控制程序
static long gec6818_motor_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
{switch(cmd) {case 0:if (arg > MOTOR_NUM) {return -EINVAL;}motor_init();printk("Motor Stop.\n");break;case 1:if (arg > MOTOR_NUM) {return -EINVAL;}motor_rollback();printk("Motor Rollback.\n");break;case 4:if (arg > MOTOR_NUM) {return -EINVAL;}		motor_foreward();printk("Motor Foreward.\n");break;default:return -EINVAL;}return 0;
}
//文件操作集
static struct file_operations gec6818_motor_dev_fops = {.owner			= THIS_MODULE,.unlocked_ioctl	= gec6818_motor_ioctl,.open = gec6818_motor_open
};
//雜項設備
static struct miscdevice gec6818_motor_dev = {.minor			= MISC_DYNAMIC_MINOR,.name			= DEVICE_NAME,.fops			= &gec6818_motor_dev_fops,
};//驅動的初始化函數--->從內核中申請資源(內核、中斷、設備號、鎖....)
static int __init gec6818_motor_dev_init(void)
{int ret;int i;for (i = 0; i < MOTOR_NUM; i++) {ret = gpio_request(motor_gpios[i], "MOTOR");if (ret) {printk("%s: request GPIO %d for MOTOR failed, ret = %d\n", DEVICE_NAME,motor_gpios[i], ret);return ret;}gpio_direction_output(motor_gpios[i],0);}gpio_set_value(motor_gpios[0], 0);gpio_set_value(motor_gpios[1], 0);ret = misc_register(&gec6818_motor_dev);printk(DEVICE_NAME"\tinitialized\n");return ret;
}//驅動退出函數 --->將申請的資源還給內核
static void __exit gec6818_motor_dev_exit(void) 
{int i;for (i = 0; i < MOTOR_NUM; i++) {gpio_free(motor_gpios[i]);}misc_deregister(&gec6818_motor_dev);
}
module_init(gec6818_motor_dev_init);  //驅動的入口函數會調用一個用戶的初始化函數
module_exit(gec6818_motor_dev_exit);  //驅動的出口函數會調用一個用戶的退出函數
//驅動的描述信息: #modinfo  *.ko , 驅動的描述信息并不是必需的。
MODULE_AUTHOR("sugar@NNLG");                         //驅動的作者
MODULE_DESCRIPTION("Dc_Motor of driver");           //驅動的描述
MODULE_LICENSE("GPL");                              //遵循的協議

?

3.1.2.2 光照強度調控

????????光照強度的調控中,采用步進電機對超過閾值的光照強度進行控制。VDD_5V為電路供電,C58和C59組成濾波電路,穩定電源電壓。ULN2003A是達林頓管陣列,起電流放大作用。微控制器通過XEINT16_B、XEINT17_B、XEINT18_B、XEINT19_B引腳輸出控制信號,輸入到 ULN2003A 的對應引腳,經放大后從其1C-7C引腳輸出,通過BA-BD線路驅動步進電機轉動。步進電機可連接如百葉窗等裝置,通過轉動改變百葉窗葉片角度或位置,進而控制進入室內或檢測區域的光線量,達到調節光照強度的目的。

直流電機驅動代碼如下所示:
#include <linux/module.h>       /* Needed by all modules */
#include <linux/kernel.h>       /* Needed for KERN_ALERT */
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <mach/irqs.h>
#include <linux/gpio.h>
#include <asm/gpio.h>
#include <asm/delay.h>
#include <linux/clk.h>
#include <mach/gpio.h>
#include <mach/soc.h>
#include <mach/platform.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
#define DEVICE_NAME     "stepmotor" //設備名字
#define BUF_SIZE 	1024        //Buf的大小static char tmpbuf[BUF_SIZE];
static unsigned int StepMajor=0;
static unsigned int StepMinor=0;
static struct cdev *step_cdev;
static dev_t dev;
struct class *my_class;
//結構體步進電機
struct stepmotor_des {int io_port;char *name;
} ;
//步進電機的管腳和名字
struct stepmotor_des  step_motor[] = {??????//定義管腳和名字,需要查看原理圖修改
};
#define  SIZE   ARRAY_SIZE(step_motor) //大小
//字符設備打開
static int step_chardev_open(struct inode *inode,struct file *file)
{// 4 9 3 5int i;//管腳申請for(i=0;i<SIZE;i++){gpio_request( step_motor[i].io_port,step_motor[i].name );gpio_direction_output( step_motor[i].io_port,0 );}printk("open major=%d, minor=%d\n", imajor(inode), iminor(inode));return 0;
}
//字符設備釋放
static int step_chardev_release(struct inode *inode,struct file *file)
{int i;for(i=0;i<SIZE;i++){gpio_free(step_motor[i].io_port);}//printk("close major=%d, minor=%d\n", imajor(inode), iminor(inode));return 0;
}
//字符設備讀值
static ssize_t step_chardev_read(struct file *file,char __user *buf,size_t const count,loff_t *offset)
{if(count < BUF_SIZE){if(copy_to_user(buf,tmpbuf,count)){printk("copy to user fail \n");return -EFAULT;}}else{printk("read size must be less than %d\n", BUF_SIZE);return -EINVAL;}*offset += count;return count;
}
//字符設備寫值
static ssize_t step_chardev_write(struct file *file, const char __user *buf,size_t const count,loff_t *offset)
{if(count < BUF_SIZE){if(copy_from_user(tmpbuf,buf,count)){printk("copy from user fail \n");return -EFAULT;}}else{printk("size must be less than %d\n", BUF_SIZE);return -EINVAL;}*offset += count;return count;
}
//字符設備ied的正傳
void step_motor_forward(int speed)
{gpio_direction_output( step_moter[0].io_port,1);gpio_direction_output( step_moter[1].io_port,0);gpio_direction_output( step_moter[2].io_port,0);gpio_direction_output( step_moter[3].io_port,0);mdelay(speed);gpio_direction_output( step_moter[0].io_port,0);gpio_direction_output( step_moter[1].io_port,1);mdelay(speed);gpio_direction_output(step_moter[1].io_port,0);gpio_direction_output( step_moter[2].io_port,1);mdelay(speed);gpio_direction_output(step_moter[2].io_port,0);gpio_direction_output( step_moter[3].io_port,1);mdelay(speed);	
}
字符設備
void step_motor_backward(int speed)
{gpio_direction_output( step_motor[0].io_port,1);gpio_direction_output( step_motor[1].io_port,0);gpio_direction_output( step_motor[2].io_port,0);gpio_direction_output( step_motor[3].io_port,0);mdelay(speed);gpio_direction_output( step_motor[0].io_port,1);gpio_direction_output( step_motor[3].io_port,1);mdelay(speed);gpio_direction_output( step_motor[3].io_port,0);gpio_direction_output( step_motor[2].io_port,1);mdelay(speed);gpio_direction_output( step_motor[2].io_port,0);gpio_direction_output( step_motor[1].io_port,1);mdelay(speed);	
}//字符設備控制函數
static long step_chardev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{printk("test-ioctl: param %u %lu\n", cmd, arg);switch(cmd){case 1:{step_motor_forward(arg);break;}case 2:{step_motor_backward(arg);break;}case 3:{step_motor_backward(arg);break;}default:printk(" Unkown key");break;}return 0;
}
文件操作集
static struct file_operations chardev_fops={.owner = THIS_MODULE,.open = step_chardev_open,.release = step_chardev_release,.read = step_chardev_read,.write = step_chardev_write,.unlocked_ioctl = step_chardev_ioctl,//.ioctl = step_chardev_ioctl,
};//驅動的初始化函數--->從內核中申請資源(內核、中斷、設備號、鎖....)
static int  __init  step_motor_init(void)
{	int result;if(StepMajor){dev=MKDEV(StepMajor,StepMinor);result=register_chrdev_region(dev,1,DEVICE_NAME);} else {result=register_chrdev_region(dev,1,DEVICE_NAME);StepMajor=MAJOR(dev);dev=MKDEV(StepMajor,StepMinor);}if(result<0){printk(KERN_WARNING"LED: cannot get major %d \n",StepMajor);return result;}step_cdev=cdev_alloc();cdev_init(step_cdev,&chardev_fops);step_cdev->owner=THIS_MODULE;result=cdev_add(step_cdev,dev,1);if(result)printk("<1>Error %d while register led device!\n",result);my_class = class_create(THIS_MODULE,DEVICE_NAME);if(IS_ERR(my_class)){printk("Failed to create class \n");return -1;}device_create(my_class,NULL,dev,NULL,DEVICE_NAME);	return 0;
}
//驅動退出函數 --->將申請的資源還給內核
static void __exit  step_motor_exit(void)
{unregister_chrdev_region(MKDEV(StepMajor,StepMinor),1);cdev_del(step_cdev);	device_destroy(my_class,MKDEV(StepMajor,StepMinor));class_destroy(my_class);	
}module_init(step_motor_init); //驅動的入口函數會調用一個用戶的初始化函數
module_exit(step_motor_exit); //驅動的出口函數會調用一個用戶的退出函數
//驅動的描述信息: #modinfo  *.ko , 驅動的描述信息并不是必需的。
MODULE_AUTHOR("SUGAR@NNLG");                         //驅動的作者
MODULE_DESCRIPTION("Step_Motor of driver");         //驅動的描述
MODULE_LICENSE("GPL");                              //遵循的協議

?

3.1.2.3 負載調控

????????負載調控中,在環境變量超過閾值時,采用繼電器吸合,改變電路連接狀態,切斷負載的供電。在該電路中,VDD_5V為電源,C64和C65起到濾波作用,穩定電源電壓。當環境變量(如溫度、煙霧濃度等 )超過閾值,微控制器通過 XEINT23_B引腳輸出信號,經R107限流后輸入到三極管Q1(8050)的基極,使Q1導通。此時繼電器U22(HK4100)的線圈得電,繼電器吸合,改變電路連接狀態,切斷負載(通過USBJACK連接的設備)的供電。D17(1N4004)為續流二極管,防止繼電器線圈斷電時產生的反向電動勢損壞元件。D18(LED-B)可用于指示繼電器工作狀態。

3.1.3 狀態指示與報警監測模塊

3.1.3.1 發光小燈狀態指示

????????發光小燈用于指示溫度、濕度、光照強度和煙霧濃度是否超過閾值,對應燈亮起,表示該參數值超過閾值。

????????溫度指示燈在ADC模塊中,通過ADC通道(如XadcAIN1、XadcAIN2、XadcAIN3)檢測溫度傳感器信號,并通過GPIO控制LED;濕度指示燈在ADC模塊中,與DHT11傳感器相關,通過XEINT24_B或XEINT26等GPIO控制LED;光照強度指示燈在 LIGHT SENSOR部分,通過XadcAIN1或 XadcAIN2檢測光照,LED連接到VDD_IO 或 VDD18V;煙霧濃度指示燈在MQ-2模塊或通過ADC檢測煙霧傳感器信號,LED控制信號可連接到XEINT27或XEINT29。

發光指示燈驅動代碼如下所示:
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include "led_cmd.h"
#include <linux/io.h>#define DEVICE_NAME		"led4"                //設備名字
struct resource *myLedRes;
unsigned int led_gpio[4];
//led_open 函數
static int led_open(struct inode *inode, struct file *filp)
{printk(DEVICE_NAME ":open!!!\n");return 0;
}
//LED 控制函數
static long gec6818_leds_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
{#if 1printk("led_num = %d \n", LED_NUM);if(_IOC_TYPE(cmd) != LED_MAGIC) return - EINVAL;if(_IOC_NR(cmd) > LED_MAX_NR) return - EINVAL; gpio_set_value(led_gpio[_IOC_NR(cmd)], arg);printk(DEVICE_NAME": %d %lu\n", _IOC_NR(cmd), arg);#endif//printk("xxxx %lu, %d xxxxx \n", cmd, arg);return 0;
}
//文件操作集
static struct file_operations led_fops = {.owner  = THIS_MODULE,.open = led_open,.unlocked_ioctl = gec6818_leds_ioctl,
};
//雜項設備
static struct miscdevice misc = {.minor		= MISC_DYNAMIC_MINOR, //雜項設備主設備號10 ,自動分配次設備號.name		= DEVICE_NAME,    //生成設備文件的名字.fops		= &led_fops,
};
//device  和 driver 匹配成功后,會自動調用該函數
//*dev -->與該platform driver匹配的platform device
static int __devinit gec6818_led_probe(struct platform_device *pdev)
{int i, ret;for(i=0; i< 4; i++){myLedRes = platform_get_resource(pdev, IORESOURCE_MEM,i);if(myLedRes == NULL){printk("<0>""Error while get the myLedRes %i\n",i);return -EBUSY;}else{led_gpio[i] = myLedRes->start;ret = gpio_request(led_gpio[i],"led_gpio");if(ret <0 ){printk("fail to request led gpio \n");return ret;}gpio_direction_output(led_gpio[i], 0);}}ret = misc_register(&misc);   //注冊雜項設備pr_err(DEVICE_NAME"\tinitialized\n");return ret;
}
static int __devexit gec6818_led_remove(struct platform_device *dev)
{int i;//釋放管腳for (i = 0; i < LED_NUM; i++){gpio_free(led_gpio[i]);}misc_deregister(&misc);return 0;
}
static struct platform_driver gec6818_led_driver = {.probe  = gec6818_led_probe,.remove = __devexit_p(gec6818_led_remove),.driver = {.owner = THIS_MODULE,.name  = "led4_driver",	  //buttons_driver必須和設備的名字一致。},	
};
//驅動的初始化函數--->從內核中申請資源
static int __init led_dev_init(void)
{int ret;ret = platform_driver_register(&gec6818_led_driver);return ret;
}
//驅動退出函數 --->將申請的資源還給內核
static void __exit led_dev_exit(void)
{platform_driver_unregister(&gec6818_led_driver);
}
module_init(led_dev_init);                       //驅動的入口函數會調用一個用戶的初始化函數
module_exit(led_dev_exit);                       //驅動的出口函數會調用一個用戶的退出函數
//驅動的描述信息: #modinfo  *.ko , 驅動的描述信息并不是必需的。
MODULE_AUTHOR("sugar@NNLG");                         //驅動的作者
MODULE_DESCRIPTION("led of driver");            //驅動的描述
MODULE_LICENSE("GPL");                              //遵循的協議
MODULE_VERSION("v1.0");

編譯過程省略。

3.1.3.1 報警監測

????????報警檢測中,采用蜂鳴器,通過PWN脈沖寬度調制技術實現報警功能。VDD_5V為蜂鳴器Buzzer1提供工作電源。微控制器輸出的PWM信號通過PWM2引腳,經電阻R117(1KΩ)限流后輸入到三極管Q3(型號9014)的基極。當PWM信號為高電平時,三極管Q3導通,使得電源電壓能夠施加到蜂鳴器兩端,蜂鳴器得電發聲;當PWM信號為低電平時,三極管Q3截止,蜂鳴器失電停止發聲 。通過改變PWM信號的頻率和占空比,可控制蜂鳴器發出不同頻率和響度的聲音,從而實現不同模式的報警功能。

蜂鳴器驅動代碼如下所示:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <cfg_type.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <mach/platform.h>
#include <mach/devices.h>
#include <mach/soc.h>
#include "led_cmd.h"
#define DEVICE_NAME				"pwm"
#define NS_IN_1HZ				(1000000000UL)
#define BUZZER_PWM_ID			2
#define BUZZER_PMW_GPIO			(????)static struct pwm_device *pwm2buzzer;
static struct semaphore lock;
static void pwm_set_freq(unsigned long freq) {int period_ns = NS_IN_1HZ / freq;pwm_config(pwm2buzzer, period_ns / 2, period_ns);pwm_enable(pwm2buzzer);
}
static void pwm_stop(void) {pwm_config(pwm2buzzer, 0, NS_IN_1HZ / 100);pwm_disable(pwm2buzzer);
}
static int gec6818_pwm_open(struct inode *inode, struct file *file) {if (!down_trylock(&lock))return 0;elsereturn -EBUSY;
}
static int gec6818_pwm_close(struct inode *inode, struct file *file) {up(&lock);return 0;
}
static long gec6818_pwm_ioctl(struct file *filep, unsigned int cmd,unsigned long arg)
{//if(_IOC_TYPE(cmd) != PWM_MAGIC) return - EINVAL;//if(_IOC_NR(cmd) > PWM_MAX_NR) return - EINVAL; switch ( ????) {    //根據命令序列號控制蜂鳴器的狀態case BUZZER_IOCTL_SET_FREQ:if (arg == 0)return -EINVAL;pwm_set_freq(arg);break;case BUZZER_IOCTL_STOP:default:pwm_stop();break;}return 0;
}
static struct file_operations gec6818_pwm_ops = {.owner			= THIS_MODULE,.open			= gec6818_pwm_open,.release		= gec6818_pwm_close, .unlocked_ioctl	= gec6818_pwm_ioctl,
};
static struct miscdevice gec6818_misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &gec6818_pwm_ops,
};
static int __init gec6818_pwm_dev_init(void) {int ret;ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME);if (ret) {printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO);return ret;}gpio_direction_output(BUZZER_PMW_GPIO, 0);pwm2buzzer = pwm_request(BUZZER_PMW_ID, DEVICE_NAME);if (IS_ERR(pwm2buzzer)) {printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME);return -ENODEV;}pwm_stop();gpio_free(BUZZER_PMW_GPIO);//init_MUTEX(&lock);sema_init(&lock,1);  //ret = misc_register(&gec6818_misc_dev);printk(DEVICE_NAME "\tinitialized\n");return ret;
}
static void __exit gec6818_pwm_dev_exit(void) {pwm_stop();misc_deregister(&gec6818_misc_dev);
}
module_init(gec6818_pwm_dev_init);
module_exit(gec6818_pwm_dev_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("GEC Inc.");
MODULE_DESCRIPTION("S5PV6818 PWM Driver");

?四、QT頁面設計

4.1?新建項目工程

1、點擊菜單:File→New File or Project→Qt→Qt Desinger Form Class→Choose。

2、關聯一個UI設計文件Dialog with Buttons Bottom→Next。

3、在Qt項目中選擇類名:在Class name中輸入類名→Next。

4、雙擊.ui結尾的文件,進入界面設計編輯器,通過布局管理、屬性編輯、信號與槽連接的步驟實現進行多個UI界面的設計。

4.2 界面跳轉

????????Qt界面跳轉可通過多種方式實現:

????????多窗口切換:創建獨立窗口實例,通過show()和hide()方法控制顯示/隱藏(如主窗口與對話框切換),支持窗口間傳參和狀態保持。

???????QStackedWidget:在同一窗口內管理多個頁面,通過setCurrentIndex()按索引切換,適合向導或多步驟界面,輕量級且無需頻繁創建/銷毀窗口。

????????QTabWidget:以選項卡形式組織頁面,用戶點擊選項卡標簽切換,界面直觀,適合分類展示內容。
這些方式靈活適配不同場景,通過合理選擇可實現流暢的用戶界面導航。

????????在本次環境系統設計中,通過loginDlg類的on_loginBtn_clicked槽函數中實現界面跳轉。當用戶點擊登錄按鈕,若用戶名輸入框內容(去除首尾空格后)為“star”且密碼輸入框內容為“123456”,則創建Led窗口實例,設置其固定大小為 800×480,顯示該窗口并關閉當前登錄窗口;若用戶名或密碼錯誤,彈出警告消息框提示錯誤,清空用戶名和密碼輸入框內容,并將光標移至用戶名輸入框具體代碼參數設置。

4.3 信號與槽的關聯

????????在Qt中,信號與槽是對象間通信的核心機制,信號由對象狀態改變時自動發出(如按鈕點擊),槽是接收信號的函數(如自定義處理函數或 Lambda 表達式)。通過QObject::connect()函數可手動關聯信號與槽,格式為connect(信號發送者,&發送者類::信號,信號接收者,&接收者類::槽),也可通過Qt Designer實現自動關聯(槽名需遵循on_對象名_信號名()規則。信號與槽的參數類型需匹配,支持參數過濾(槽可只接收部分信號參數),這種機制實現了組件間的松耦合,使代碼結構清晰且易于維護。如下圖3-37,在登陸界面的ui文件下對“告警值:”使用go to slot,能夠跳轉到對應的槽函數,快速關聯信號與槽,實現組件的交互邏輯。

4.4 驅動程序的調用

????????在Qt中通過“pen()函數調用驅動程序:首先需要包含對應的“<fcntl.h><unistd.h>頭文件,然后使用open(/dev/設備名, O_RDWR)以讀寫模式打開設備文件并獲取文件描述符(若返回值小于0則打開失敗),接著通過read()write()ioctl()函數進行數據讀寫或設備控制,操作完成后使用close()關閉文件描述符,同時需注意權限問題、進行錯誤處理,復雜場景下可將操作放入獨立線程避免阻塞UI

????????例如對直流電機驅動程序的調用,首先通過open函數以讀寫模式(O_RDWR)打開直流電機設備文件/dev/dc_motor ,嘗試獲取對直流電機驅動程序的訪問權限。文件描述符fd用于后續對設備的操作。當open函數返回的fd小于 0 ,即設備文件打開失敗時,使用perror打印錯誤信息,然后通過exit(1)終止程序。接著,使用ioctl函數對已打開的直流電機設備進行控制。通過傳入不同的flag值(4 代表正轉、1 代表反轉、0 代表停止 ),向驅動程序傳遞控制指令。最后,使用close函數關閉之前打開的設備文件描述符fd,釋放系統資源。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/85484.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/85484.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/85484.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++中std::transform詳解和應用代碼示例

std::transform 是 C 標準庫中非常常用的算法之一&#xff0c;屬于 <algorithm> 頭文件。它的作用是將一個&#xff08;或兩個&#xff09;序列中的元素通過某個函數進行變換&#xff0c;并將結果輸出到另一個序列中。 一、std::transform 作用總結 std::transform 支持…

Yolov5 使用

1.開發背景 在已有的 Conda 環境下實現目標檢測標定。 2.開發需求 實現演示例子的圖片標定。 3.開發環境 Ubuntu20.04 Conda Yolov5 4.實現步驟 4.1 安裝環境 # 創建環境 python 版本建議 3.9 以上 conda create -n yolov5 python3.9# 進入環境 conda activate yolov5# …

資深Java工程師的面試題目(四)性能優化

以下是針對Java性能優化的面試題&#xff0c;涵蓋前后端技術棧的常見優化方式&#xff0c;適合評估候選人對性能調優的理解和實際應用能力&#xff1a; 1. JVM性能調優 題目: 請說明JVM垃圾回收&#xff08;GC&#xff09;的常見類型及其適用場景&#xff0c;并描述如何通過J…

火山引擎TTS使用體驗

文章目錄 前言1. 簡介1.1 能力體驗1.2 功能特性1.3 音色列表1.4 收費情況 2. 開啟服務2.1 創建應用2.3 使用服務介紹 3.Websocket接入演示3.1 編寫demo3.2 代碼解釋3.4運行demo 4. 參考鏈接 前言 語音合成TTS&#xff08;text to Speech&#xff09;是我覺得后續開發產品所不可…

Django中使用流式響應,自己也能實現ChatGPT的效果

最近在研究ChatGPT的時候&#xff0c;想通過openai提供的接口使國內用戶也可以無限制訪問&#xff0c;于是打算基于django開發一款應用。頁面的渲染也得想ChatGPT一樣采用流式響應&#xff0c;django中StreamingHttpResponse是支持流式響應的一種方式。 django 代碼 class Ch…

Python Redis 簡介

Redis 是一個高性能的內存鍵值數據庫&#xff0c;支持多種數據結構&#xff08;字符串、列表、哈希、集合等&#xff09;&#xff0c;常用于緩存、消息隊列和實時數據處理。Python 通過 redis-py 庫與 Redis 交互。 核心功能 內存存儲&#xff1a;數據存儲在內存中&#xff0c…

mac安裝whistle代理抓包工具(支持mock)

工具地址&#xff1a;https://wproxy.org/whistle/ 1、 安裝nodejs環境 參考方法&#xff1a;https://github.com/nvm-sh/nvm 1&#xff09;安裝 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash如圖&#xff0c;安裝成功 2&#xff09;…

基于 mydumper 實現 MySQL 定期全量備份、恢復方案

一、Mydumper 工具介紹 mydumper 是一款社區開源的邏輯備份工具,由 C 語言編寫,與 MySQL 官方提供的 mysqldump 相比,它具有更高的性能和更多的功能,例如: ? 支持多線程導出數據,速度更快; ? 支持一致性備份; ? 支持將導出文件壓縮,節約空間; ? 支持多線程恢復;…

C++中,std::async 一個用于異步編程的工具

在C中&#xff0c;std::async 是一個用于異步編程的工具&#xff0c;它允許你在一個單獨的線程中執行任務&#xff0c;并返回一個 std::future 對象&#xff0c;通過這個對象可以獲取任務的結果或者檢查任務的狀態。 基本用法1 lambda 表達式 #include <iostream> #incl…

【Linux驅動開發 ---- 4_驅動開發框架和 API】

Linux驅動開發 ---- 4_驅動開發框架和 API 目錄 Linux驅動開發 ---- 4_驅動開發框架和 API&#x1f3af; 目標&#xff1a;&#x1f4cc; 1. Linux 設備模型&#xff08;Linux Device Model&#xff09;**設備模型的核心概念**&#xff1a; &#x1f4cc; 2. 設備樹&#xff08…

實景VR展廳建設流程

實景VR展廳&#xff1a;建設流程、用途、案例與未來發展 隨著虛擬現實&#xff08;VR&#xff09;技術的發展&#xff0c;實景VR展廳作為一種創新的展示方式&#xff0c;正在各個領域得到廣泛應用。實景VR展廳提供沉浸式的體驗&#xff0c;豐富展示內容和形式&#xff0c;為觀…

android下拉欄添加媒體音量調節

參考下拉欄的屏幕亮度調節&#xff0c;添加媒體音量調節。 平臺信息&#xff1a; MSM8909.LA.3.1.2_AOSP PLATFORM_VERSION9 BUILD_IDPKQ1.190903.001 效果圖 布局文件與音量圖標 Index: frameworks/base/packages/SystemUI/res/layout/quick_settings_media_volume_dialog.x…

VS Code 配置ROS2開發環境常見問題記錄

1、ctrlshiftp后找不到C/C: Edit configurations 安裝或重裝C插件。 參考鏈接&#xff1a; 搜索C/C: Edit configurations顯示no matching command問題https://www.cnblogs.com/hunghau/p/17195622.html 2、ROS2 API無法轉到定義 &#xff08;1&#xff09;在c_cpp_proper…

Docker Desktop搭建RocketMQ的完整教程

Docker Desktop搭建RocketMQ圖文教程 1. 準備工作 已安裝Docker Desktop&#xff08;本地安裝方法參考上一節教程&#xff09;。需部署三個組件&#xff1a;NameServer、Broker、Console&#xff08;管理界面&#xff09;。 2. 創建目錄和文件 在任意盤&#xff08;如D盤&am…

算法35天|1049. 最后一塊石頭的重量 II、 494. 目標和、 474.一和零

1049. 最后一塊石頭的重量 II 題目 思路與解法 class Solution { public:int lastStoneWeightII(vector<int>& stones) {int sum 0;for(int i0;i<stones.size();i){sum stones[i];}// 問題轉換為&#xff1a;// 先求得&#xff0c;背包容量為target時&#x…

AWS S3拒絕非https的請求訪問

問題 aws s3桶&#xff0c;安全要求必須強制使用ssl加密訪問&#xff0c;即https。需要添加一個策略拒絕所有不是https的訪問s3桶請求。 解決 在對于桶添加相關拒絕策略即可。如下&#xff1a; {"Version": "2012-10-17","Statement": [{&qu…

GitLab CVE-2025-4278 安全漏洞解決方案

本分分享極狐GitLab 補丁版本 18.0.2, 17.11.4, 17.10.8 的詳細內容。這幾個版本包含重要的缺陷和安全修復代碼&#xff0c;我們強烈建議所有私有化部署用戶應該立即升級到上述的某一個版本。對于極狐GitLab SaaS&#xff0c;技術團隊已經進行了升級&#xff0c;無需用戶采取任…

Async、await是什么?跟promise有什么區別?使用的好處是什么

Async/Await 與 Promise 的深度解析 一、基本概念 1. Promise Promise 是 ES6 引入的異步編程解決方案&#xff0c;表示一個異步操作的最終完成&#xff08;或失敗&#xff09;及其結果值。 function fetchData() {return new Promise((resolve, reject) > {setTimeout(…

MySQL數據庫中所有表的空間占用與行數統計

查看某個數據庫中所有表的空間與行數統計 SELECT TABLE_NAME AS 表名,TABLE_ROWS AS 行數,ROUND(DATA_LENGTH / 1024 / 1024, 2) AS 數據大小(MB),ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS 索引大小(MB),ROUND((DATA_LENGTH INDEX_LENGTH) / 1024 / 1024, 2) AS 總占用空間(…

el-upload 點擊上傳按鈕前先判斷條件滿足再彈選擇文件框

解決思路&#xff1a; 先寫一個上傳按鈕&#xff0c;點擊上傳按鈕后判斷條件是否滿足&#xff0c;滿足則顯示上傳組件并使用ref來控制點擊事件&#xff0c;隱藏自身。 注&#xff1a;上傳成功或者上傳失敗時或者上傳前判斷條件添加不滿足return將this.isShow true 代碼部分…