在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux小項目-倒車影像功能設計

DS小龍哥-嵌入式技術 ? 來源:DS小龍哥-嵌入式技術 ? 作者:DS小龍哥-嵌入式技 ? 2022-08-14 09:13 ? 次閱讀

1. 前言

倒車影像已經是現在汽車的標配功能了,基本很多車出廠都是360全景影像,倒車影像又稱泊車輔助系統,這篇文章就采用Linux開發板完成一個倒車影像的功能。

要完成倒車影像整個項目,需要準備一個LCD屏,一個攝像頭,一個超聲波測距模塊,一個蜂鳴器;攝像頭采集車尾的實時畫面,在LCD屏上完成顯示,超聲波測距模塊用于測量車尾距離障礙物的距離,根據設置的距離跳轉PWM操作蜂鳴器實現報警提示。

當前Linux開發板采用友善之臂的Tiny4412開發板,CPU三星的EXYNOS4412,板子上帶有8G的EMMC,2G的DRR,運行的Linux版本是3.5,根文件系統采用busybox制作,這個系統是精簡的最小系統。

攝像頭采用USB免驅是攝像頭,所有不需要編寫驅動,LCD屏是友善之臂自己的7寸電容觸摸屏,驅動是官方內核自帶的,也不需要編寫;剩下的超聲波模塊,蜂鳴器,需要自己填寫驅動。

image-20220123213645806

2. 案例代碼

下面就將倒車影像項目的整個項目核心代碼依次展示出來。

2.1 聲波測距模塊

采用的超聲波模塊在淘寶上很容易買到,它的實物圖和測距原理如下:

image-20220123213943590image-20220123214019976

整個模塊只需要接4根線,兩根電源線,一個輸出觸發腳,一個回波輸出腳。輸出腳是高電平有效,為了方便計算時間,驅動代碼里需要將這個引腳注冊為中斷,設置為上升沿觸發,當收到回波時,直接進中斷調用工作隊列,在工作函數里阻塞等待引腳電平變低,然后高電平持續的計算時間,最后進行換算就得到了距離。

驅動代碼如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static unsigned int distance_irq; /*存放中斷號*/
static u32 *GPB_DAT=NULL;
static u32 *GPB_CON=NULL;

static u32 distance_time_us=0; /*表示距離的時間*/
static u8 distance_flag=0;

/*聲明等待隊列頭*/
static DECLARE_WAIT_QUEUE_HEAD(distance_wait_queue);

/*
工作隊列處理函數: 
*/
static void distance_work_func(struct work_struct *work)
{
	u32 time1,time2;
	time1=ktime_to_us(ktime_get()); /*獲取當前時間,再轉換為 us 單位*/

	/*等待高電平時間結束*/
	while(gpio_get_value(EXYNOS4_GPX1(0))){}
	
	time2=ktime_to_us(ktime_get()); /*獲取當前時間,再轉換為 us 單位*/

	distance_flag=1;
	distance_time_us=time2-time1;

	/*喚醒休眠的進程*/
	wake_up(&distance_wait_queue);
	
	//printk("us=%d\n",time2-time1);   /*us/58=厘米*/
}

/*靜態方式初始化工作隊列*/
static DECLARE_WORK(distance_work,distance_work_func);

/*
中斷處理函數: 用于檢測超聲波測距的回波
*/
static irqreturn_t distance_handler(int irq, void *dev)
{
	/*調度工作隊列*/
	schedule_work(&distance_work);
	return IRQ_HANDLED;
}

static void distance_function(unsigned long data);
/*靜態方式定義內核定時器*/
static DEFINE_TIMER(distance_timer,distance_function,0,0);

/*內核定時器超時處理函數: 觸發超聲波發送方波*/
static void distance_function(unsigned long data)
{
	static u8 state=0;
	state=!state;
	
	/*更改GPIO口電平*/
	if(state)
	{
		*GPB_DAT|=1<<7;
	}
	else
	{
		*GPB_DAT&=~(1<<7);
	}
	
	/*修改定時器的超時時間*/
	mod_timer(&distance_timer,jiffies+msecs_to_jiffies(100));
}

static int distance_open(struct inode *inode, struct file *file)
{
	return 0;
}

#define GET_US_TIME 0x45612
static long distance_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long argv)
{
	u32 *us_data=(u32*)argv;
	int err;
	u32 time_us=distance_time_us;
	switch(cmd)
	{
		case GET_US_TIME:
			err=copy_to_user(us_data,&time_us,4);
			if(err!=0)printk("拷貝失敗!\n");
			break;
	}
	return 0;
}

static unsigned int distance_poll(struct file *file, struct poll_table_struct *table)
{
	unsigned int mask = 0;
	poll_wait(file,&distance_wait_queue,table);

	if(distance_flag)
	{
		distance_flag=0;
		mask|=POLL_IN;
	}
	return mask;
}

static int distance_release(struct inode *inode, struct file *file)
{
	return 0;
}

/*定義文件操作集合*/
static struct file_operations distance_fops=
{
	.open=distance_open,
	.unlocked_ioctl=distance_unlocked_ioctl,
	.poll=distance_poll,
	.release=distance_release
};


/*定義雜項設備結構體*/
static struct miscdevice distance_misc=
{
	.minor=MISC_DYNAMIC_MINOR,
	.name="tiny4412_distance",
	.fops=&distance_fops
};

static int __init tiny4412_distance_dev_init(void) 
{
	int err;
	/*1. 映射GPIO口地址*/
	GPB_DAT=ioremap(0x11400044,4);
	GPB_CON=ioremap(0x11400040,4);

	*GPB_CON&=~(0xF<<4*7);
	*GPB_CON|=0x1<<4*7; /*配置輸出模式*/
	
	/*2. 根據GPIO口編號,獲取中斷號*/
	distance_irq=gpio_to_irq(EXYNOS4_GPX1(0));
	
	/*3. 注冊中斷*/
	err=request_irq(distance_irq,distance_handler,IRQ_TYPE_EDGE_RISING,"distance_device",NULL);
	if(err!=0)printk("中斷注冊失敗!\n");
	else printk("中斷:超聲波測距驅動安裝成功!\n");

	/*4. 修改定時器超時時間*/
	mod_timer(&distance_timer,jiffies+msecs_to_jiffies(100));

	/*雜項設備注冊*/
	misc_register(&distance_misc);
	return 0;
}

static void __exit tiny4412_distance_dev_exit(void) 
{
	/*5. 注銷中斷*/
	free_irq(distance_irq,NULL);

	/*6. 停止定時器*/
	del_timer(&distance_timer);
	
	/*7. 取消IO映射*/
	iounmap(GPB_DAT);
	iounmap(GPB_CON);

	/*注銷雜項設備*/
	misc_deregister(&distance_misc);
	
	printk("中斷:超聲波測距驅動卸載成功!\n");
}

module_init(tiny4412_distance_dev_init);
module_exit(tiny4412_distance_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tiny4412 wbyq");
復制代碼

2.2 蜂鳴器驅動代碼

蜂鳴器需要根據測量的距離調整不同的頻率,以告訴駕駛員,后方障礙物的距離。

image-20220123215256630
static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
{
    struct pwm_device *pwm = platform_get_drvdata(pdev);
    pwm->period_ns = 0;
    pwm->duty_ns = 0;
?
    return 0;
}
?
static int s3c_pwm_resume(struct platform_device *pdev)
{
    struct pwm_device *pwm = platform_get_drvdata(pdev);
    unsigned long tcon;
?
    /* Restore invertion */
    tcon = __raw_readl(S3C2410_TCON);
    tcon |= pwm_tcon_invert(pwm);
    __raw_writel(tcon, S3C2410_TCON);
?
    return 0;
}
?
static struct platform_driver s3c_pwm_driver = {
    .driver     = {
        .name   = "s3c24xx-pwm",
        .owner  = THIS_MODULE,
    },
    .probe      = s3c_pwm_probe,
    .remove     = __devexit_p(s3c_pwm_remove),
    .suspend    = s3c_pwm_suspend,
    .resume     = s3c_pwm_resume,
};
?
static int __init pwm_init(void)
{
    int ret;
?
    clk_scaler[0] = clk_get(NULL, "pwm-scaler0");
    clk_scaler[1] = clk_get(NULL, "pwm-scaler1");
?
    if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) {
        printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__);
        return -EINVAL;
    }
?
    ret = platform_driver_register(&s3c_pwm_driver);
    if (ret)
        printk(KERN_ERR "%s: failed to add pwm driver\n", __func__);
?
    return ret;
}
復制代碼

2.3 應用層框架代碼

應用層使用了兩個線程:

線程1實時讀取USB攝像頭的圖像,在LCD屏上實時顯示,免驅攝像頭框架V4L2有一套標準的ioctl指令,可以對攝像頭進行配置,比如:輸出分辨率、幀率、格式等。然后再通過mmap映射攝像頭采集緩沖區到應用層,最后通過poll函數監聽攝像頭的數據,讀取實時顯示。

線程2采集超聲波測量的距離距離,根據測量的距離調整PWM占空比,控制蜂鳴器的頻率。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "framebuffer.h"

#define PWM_DEVICE "/dev/pwm"  /*PWM方波設備文件*/
#define DISTANCE_DEVICE "/dev/tiny4412_distance" /*超聲波測距設備文件*/
#define UVC_VIDEO_DEVICE "/dev/video15"  /*UVC攝像頭設備節點*/

#define GET_US_TIME 0x45612     /*獲取超聲波測量的距離: ioctl命令*/
#define PWM_IOCTL_SET_FREQ		1 /*控制PWM方波頻率: ioctl命令*/
#define PWM_IOCTL_STOP			0 /*停止PWM方波輸出: ioctl命令*/

int distance_fd;  /*超聲波設備的文件描述符*/
int pwm_fd;       /*PWM方波設備的文件描述符*/
int uvc_video_fd; /*UVC攝像頭設備文件描述符*/
int Image_Width;  /*圖像的寬度*/
int Image_Height; /*圖像的高度*/


unsigned char *video_memaddr_buffer[4]; /*存放攝像頭映射到進程空間的緩沖區地址*/

/*
函數功能: 用戶終止了進程調用
*/
void exit_sighandler(int sig)
{
	//停止PWM波形輸出,關閉蜂鳴器
	ioctl(pwm_fd,PWM_IOCTL_STOP,0);
	close(pwm_fd);
	close(distance_fd);
	exit(1);
}

/*
函數功能: 讀取超聲波數據的線程
*/
void *distance_Getpthread_func(void *dev)
{
	/*1. 打開PWM方波驅動*/
	pwm_fd=open(PWM_DEVICE,O_RDWR);
	if(pwm_fd<0) //0 1 2
	{
		printf("%s 設備文件打開失敗\n",PWM_DEVICE);
		/*退出線程*/
		pthread_exit(NULL); 
	}

	/*2. 打開超聲波測距設備*/
	distance_fd=open(DISTANCE_DEVICE,O_RDWR);
	if(distance_fd<0) //0 1 2
	{
		printf("%s 設備文件打開失敗\n",DISTANCE_DEVICE);
		/*退出線程*/
		pthread_exit(NULL); 
	}

	/*3. 循環讀取超聲波測量的距離*/
	struct pollfd fds;
	fds.fd=distance_fd;
	fds.events=POLLIN;
	int data;
	while(1)
	{
		poll(&fds,1,-1);
		ioctl(distance_fd,GET_US_TIME,&data);
		printf("距離(cm):%0.2f\n",data/58.0);
		data=data/58;
		if(data>200) /*200厘米: 安全區域*/
		{
			//停止PWM波形輸出,關閉蜂鳴器
			ioctl(pwm_fd,PWM_IOCTL_STOP,0);
		}
		else if(data>100) /*100厘米: 警告區域*/
		{
			printf("警告區域!\n");
			ioctl(pwm_fd,PWM_IOCTL_SET_FREQ,2);
		}
		else /*小于<100厘米: 危險區域*/
		{
			printf(" 危險區域!\n");
			ioctl(pwm_fd,PWM_IOCTL_SET_FREQ,10);
		}
		
		//ioctl(pwm_fd,PWM_IOCTL_SET_FREQ,pwm_data);
		/*倒車影像: 測距有3個檔位*/
	}
}


/*
函數功能: UVC攝像頭初始化
返回值: 0表示成功
*/
int UVCvideoInit(void)
{
	/*1. 打開攝像頭設備*/
	uvc_video_fd=open(UVC_VIDEO_DEVICE,O_RDWR);
	if(uvc_video_fd<0)
	{
		printf("%s 攝像頭設備打開失敗!\n",UVC_VIDEO_DEVICE);
		return -1;
	}
	
	/*2. 設置攝像頭的屬性*/
	struct v4l2_format format;
	memset(&format,0,sizeof(struct v4l2_format));
	format.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*表示視頻捕獲設備*/
	format.fmt.pix.width=800;  /*預設的寬度*/
	format.fmt.pix.height=480; /*預設的高度*/
	format.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV; /*預設的格式*/
	format.fmt.pix.field=V4L2_FIELD_ANY; /*系統自動設置: 幀屬性*/
	if(ioctl(uvc_video_fd,VIDIOC_S_FMT,&format)) /*設置攝像頭的屬性*/
	{
		printf("攝像頭格式設置失敗!\n");
		return -2;
	}
	
	Image_Width=format.fmt.pix.width;
	Image_Height=format.fmt.pix.height;
		
	printf("攝像頭實際輸出的圖像尺寸:x=%d,y=%d\n",format.fmt.pix.width,format.fmt.pix.height);
	if(format.fmt.pix.pixelformat==V4L2_PIX_FMT_YUYV)
	{
		printf("當前攝像頭支持YUV格式圖像輸出!\n");
	}
	else
	{
		printf("當前攝像頭不支持YUV格式圖像輸出!\n");
		return -3;
	}

	/*3. 請求緩沖區: 申請攝像頭數據采集的緩沖區*/
	struct v4l2_requestbuffers req_buff;
	memset(&req_buff,0,sizeof(struct v4l2_requestbuffers));
	req_buff.count=4; /*預設要申請4個緩沖區*/
	req_buff.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*視頻捕獲設備*/
	req_buff.memory=V4L2_MEMORY_MMAP; /*支持mmap內存映射*/
	if(ioctl(uvc_video_fd,VIDIOC_REQBUFS,&req_buff)) /*申請緩沖區*/
	{
		printf("申請攝像頭數據采集的緩沖區失敗!\n");
		return -4;
	}
	printf("攝像頭緩沖區申請的數量: %d\n",req_buff.count);

	/*4. 獲取緩沖區的詳細信息: 地址,編號*/
	struct v4l2_buffer buff_info;
	memset(&buff_info,0,sizeof(struct v4l2_buffer));
	int i;
	for(i=0;i> 8;
		g = (y - (88 * u) - (183 * v)) >> 8;
		b = (y + (454 * u)) >> 8;

		*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
		*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
		*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
			
		if(z++)
		{
			z = 0;
			yuyv += 4;
		}
	}
}


int main(int argc,char **argv)
{
	int data;
	
	/*1. 注冊將要捕獲的信號*/
	signal(SIGINT,exit_sighandler);

	/*2. 創建線程: 采集超聲波測量的距離*/
	pthread_t threadID;
	pthread_create(&threadID,NULL,distance_Getpthread_func,NULL);
	pthread_detach(threadID); //設置分離屬性

	/*3. 初始化攝像頭*/
	UVCvideoInit();

	/*4. 初始化LCD屏*/
	framebuffer_Device_init();
	
	/*5. 循環采集攝像頭的數據*/
	struct pollfd fds;
	fds.fd=uvc_video_fd;
	fds.events=POLLIN;

	struct v4l2_buffer buff_info;
	memset(&buff_info,0,sizeof(struct v4l2_buffer));
	int index=0; /*表示當前緩沖區的編號*/
	unsigned char *rgb_buffer=NULL;

	/*申請空間:存放轉換之后的RGB數據*/
	rgb_buffer=malloc(Image_Width*Image_Height*3);
	if(rgb_buffer==NULL)
	{
		printf("RGB轉換的緩沖區申請失敗!\n");
		exit(0);
	}
	
	while(1)
	{
		/*1. 等待攝像頭采集數據*/
		poll(&fds,1,-1); 

		/*2. 取出一幀數據: 從采集隊列里面取出一個緩沖區*/
		buff_info.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;   /*視頻捕獲設備*/
		ioctl(uvc_video_fd,VIDIOC_DQBUF,&buff_info); /*從采集隊列取出緩沖區*/
		index=buff_info.index;
		//printf("采集數據的緩沖區的編號:%d\n",index);

		/*3. 處理數據: YUV轉RGB\顯示到LCD屏*/
		//video_memaddr_buffer[index]; /*當前存放數據的緩沖區地址*/

		/*3.1 將YUV數據轉為RGB格式*/
		yuv_to_rgb(video_memaddr_buffer[index],rgb_buffer,Image_Width,Image_Height);

		/*3.2 將RGB數據實時刷新到LCD屏幕上*/
		framebuffer_DisplayImages((800-Image_Width)/2,0,Image_Width,Image_Height,rgb_buffer);
		
		/*4. 將緩沖區再次放入采集隊列*/
		buff_info.memory=V4L2_MEMORY_MMAP; 	/*支持mmap內存映射*/
		buff_info.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*視頻捕獲設備*/
		buff_info.index=index; /*緩沖區的節點編號*/
		ioctl(uvc_video_fd,VIDIOC_QBUF,&buff_info); /*根據節點編號將緩沖區放入隊列*/
	}
	return 0;
};i++)>

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • lcd
    lcd
    +關注

    關注

    34

    文章

    4437

    瀏覽量

    167955
  • Linux
    +關注

    關注

    87

    文章

    11329

    瀏覽量

    209968
  • 倒車影像
    +關注

    關注

    1

    文章

    42

    瀏覽量

    5760
收藏 人收藏

    評論

    相關推薦

    Linux應用開發_倒車影像項目介紹

    介紹在嵌入式Linux下完成倒車影像小項目的流程,學習PWM驅動蜂鳴器,編寫超聲波驅動,讀取壁障距離,讀取攝像頭的畫面實時顯示。
    的頭像 發表于 06-16 13:31 ?4820次閱讀
    <b class='flag-5'>Linux</b>應用開發_<b class='flag-5'>倒車影像</b><b class='flag-5'>項目</b>介紹

    Linux驅動開發_倒車影像項目介紹

    介紹Linux倒車影像項目,完成攝像頭圖像讀取、超聲波驅動編寫、超聲波距離讀取。
    的頭像 發表于 09-17 15:47 ?2779次閱讀
    <b class='flag-5'>Linux</b>驅動開發_<b class='flag-5'>倒車影像</b><b class='flag-5'>項目</b>介紹

    倒車影像專題制作】倒車影像安裝教程_倒車影像工作原理和設計

    倒車影像又稱泊車輔助系統,或稱倒車可視系統、車載監控系統等,并應用到各種車型上,該系統讓倒車時,車后的狀況更加直觀一目了然,對于倒車安全來說是非常實用的配置之一。本專題主要幫助有車一
    發表于 08-05 11:18

    倒車影像

    倒車影像前進走路時候閃屏怎么回事
    發表于 03-24 20:16

    倒車影像系統簡介

    倒車影像系統簡介,感興趣的小伙伴們可以看看。
    發表于 08-03 16:15 ?16次下載

    倒車影像安裝方法圖文詳解

    倒車影像安裝方法圖文詳解,感興趣的小伙伴們可以看看。
    發表于 08-03 16:15 ?85次下載

    360°全景倒車影像原理解讀

    360°全景倒車影像原理解讀,感興趣的小伙伴們可以看看。
    發表于 08-03 16:28 ?220次下載

    怎樣的倒車影像才算好用

    怎樣的倒車影像才算好用,感興趣的小伙伴們可以看看。
    發表于 08-03 16:28 ?24次下載

    汽車倒車影像相關知識及如何挑選

    汽車倒車影像相關知識及如何挑選,感興趣的小伙伴們可以看看。
    發表于 08-03 16:28 ?14次下載

    倒車影像系統的工作原理

    倒車影像系統的工作原理,感興趣的小伙伴們可以看看。
    發表于 08-03 16:28 ?197次下載

    卡車倒車影像系統方案

    卡車倒車影像系統方案,感興趣的小伙伴們可以看看。
    發表于 08-03 16:32 ?30次下載

    倒車影像系統方案

    倒車影像系統方案,感興趣的小伙伴們可以看看。
    發表于 08-03 16:32 ?32次下載

    貨車導航倒車影像系統方案

    貨車導航倒車影像系統方案,感興趣的小伙伴們可以看看。
    發表于 08-03 16:32 ?25次下載

    倒車影像安裝教程

    倒車影像安裝教程,感興趣的小伙伴們可以看看。
    發表于 08-03 17:08 ?81次下載

    倒車影像安裝教程_倒車影像工作原理和設計

    倒車影像又稱泊車輔助系統,或稱倒車可視系統、車載監控系統等,并應用到各種車型上,該系統讓倒車時,車后的狀況更加直觀一目了然,對于倒車安全來說是非常實用的配置之一。本專題主要幫助有車一族
    發表于 08-03 15:49
    <b class='flag-5'>倒車影像</b>安裝教程_<b class='flag-5'>倒車影像</b>工作原理和設計
    主站蜘蛛池模板: 国产精品乱码高清在线观看| 狠狠狠狠狠狠| 最新理论三级中文在线观看| 欧美一区二区三区视频在线观看| 日本不卡视频在线视频观看| 国产午夜久久精品| 久久艹人人艹| 宅男噜噜噜66| 亚洲三级视频| 在线天堂资源| 黄网站视频在线观看| 正在播放91大神调教偷偷| 伊人久久综合网亚洲| 日韩亚洲人成在线综合| 国产精品久久在线观看| 亚洲 欧美 另类 吹潮| 一级特黄aa大片| 手机看片1024国产基地| 中国一级特黄特级毛片| 亚洲a影院| 欧美成人aaaa免费高清| 成人午夜毛片| 磁力bt种子搜索在线| 午夜视频在线观看完整高清在线| 一本大道加勒比久久| 欧美一级特黄aaaaaa在线看片 | 亚州一级毛片在线| 中文字幕精品一区二区三区视频 | 国产肥女bbwbbw| 欧美成人一区亚洲一区| 香蕉色网| 天堂资源中文官网| 亚洲成人三级| 亚洲电影一区二区| 欧美日韩一区视频| 欧美激情综合| 爱婷婷视频在线观看| 在线观看高清视频| 国产美女亚洲精品久久久综合| 亚洲涩综合| 日韩免费无砖专区2020狼|