写点什么

基于 RT-Thread 摄像头车牌图像采集系统

作者:智趣匠
  • 2024-04-22
    四川
  • 本文字数:1865 字

    阅读完需:约 6 分钟

基于RT-Thread摄像头车牌图像采集系统

一、项目简介

使用基于 RT-thread 操作系统的 AB32VG1 开发板作为主控,对 ov7670 摄像头进行图像采集,并使用串口发送图片 RGB565 格式到 PC 供 opencv 进行图像识别。 原项目设想在开发板上进行采集的同时并通过简单的二值算法和插值算法实现车牌号识别,但实践中发现开发板的 ram 并不够保存采集回来的图像信息,与数据手册中介绍的 192k 有一定差距,实现用户能使用的 ram 是 70k;同时原设想是带 lcd 屏幕的,但最后发觉 io 口数量不够,只能通过串口调试显示,但 lcd 屏幕的 spi 代码仍保留在原码中,可供参考。 目前开发板通过摄像头采集完整数据部分已经完成,并且可以通过串口 uart1 发送到上位机进行图像显示。

二、硬件说明

1.摄像头 ov7670 带 fifo:采用 csi 总线的普通 30w 摄像头。考虑到用模拟读取摄像头,io 的反转速度可能不能满足高速采集的需要,因此保险起见,直接使用带 fifo 的摄像头。sccb 总线采用全模拟的方式,跳过了所有中间层,直接操作寄存器,提高了总线的时钟。

2.串口工具 PL2302(ttl 转 RS232),一款与 pc 通讯的串口工具,免驱。

3.总接线图

三、软件说明

1.软件流程图


2.关键代码

/* 摄像头IO口采用直接操作寄存器的方式实现,极大提升io速度 */#define BSP_FIFO_RCK_PIN            "PA.5"#define BSP_FIFO_RCK_SET_LOW         (GPIOA_BASE[GPIOx] &= ~(1ul << 5))#define BSP_FIFO_RCK_SET_HIGH         (GPIOA_BASE[GPIOx] |= (1ul << 5))
/* sccb总线的初始化并设置ov7670相应寄存器 */ sccb_init();
if(sccb_write_reg(0x12, 0x80) == RT_FALSE){ return RT_FALSE; }
rt_thread_delay(50);
id1 = sccb_read_reg(0x0b); id2 = sccb_read_reg(0x0a);
rt_kprintf("id1 = 0x%02x, id2 = 0x%02xn", id1, id2);
for(rt_uint16_t i = 0;i < sizeof(ov7670_init_reg_tbl) / sizeof(ov7670_init_reg_tbl[0]);i++){ sccb_write_reg(ov7670_init_reg_tbl[0], ov7670_init_reg_tbl[1]);}
/* 开启摄像头vsync扫描线程(没有外部中断因此改用轮询的方式实现) */ rt_thread_t thread; /* 查询VSYNC线程 */ thread = rt_thread_create("ov7670_vsync", ov7670_vsync_thread_entry, RT_NULL, 1024, 5, 100);
if (thread == RT_NULL){ rt_kprintf("ov7670_vsync thread create fail!n"); return RT_FALSE; } /* 启动线程 */rt_thread_startup(thread);
/* 提取hal库实现了uart的数据发送函数 */void uart1_send(rt_uint8_t *pbuf, rt_uint32_t len){ for(rt_uint32_t i = 0;i < len;i++){ hal_uart_clrflag(UART1_BASE, UART_FLAG_TXPND); hal_uart_write(UART1_BASE, pbuf); while(hal_uart_getflag(UART1_BASE, UART_FLAG_TXPND) == 0); }}

/* LCD底层驱动代码,因为引脚不够,所以无法演示,测试可用,另外程序里也配有寄存器版本的操作代码 */
static rt_uint32_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *message){ struct rt_spi_bit_ops *ops = (struct rt_spi_bit_ops *)device->user_data;
rt_uint8_t tmp_buf[1024]; rt_memset(tmp_buf, 0, sizeof(tmp_buf));
if(message->send_buf == RT_NULL){ message->send_buf = tmp_buf; }else if(message->recv_buf == RT_NULL){ message->recv_buf = tmp_buf; }else{ return RT_FALSE; }
if (message->cs_take){ ops->set_cs(ops->data, PIN_LOW); }#ifdef SPI_DC message->length & SPI_DC ? ops->set_dc(ops->data, PIN_HIGH) : ops->set_dc(ops->data, PIN_LOW); message->length &= ~SPI_DC; /* 复原消息长度 */// rt_kprintf("message->length = %dn", message->length);#endif spi_rw_bytes(device, (rt_uint8_t *)message->send_buf, (rt_uint8_t *)message->recv_buf, message->length);
if (message->cs_release){ ops->set_cs(ops->data, PIN_HIGH); }}
static const struct rt_spi_ops spi_bit_bus_ops ={ RT_NULL, spi_bit_xfer
};
复制代码

优化思路:  1. 由于 ab32vg1 没有外部中断可以使用,ov7670 的帧同步信号 vsync 只有 500us 的高电平时间,因此为了捕捉到该信号,vsync 线程一直占用很多的资源;  2. 串口与上位通讯的速度目前最快只有 115200bps,上位机可以接受 256000bps 的速度,但将驱动改为 256000bps 后,接收会出现乱码,因此串口使用的图片数据非常缓慢。

四、项目演示


发布于: 刚刚阅读数: 4
用户头像

智趣匠

关注

凡事预则立,不预则废! 2022-06-01 加入

某公司芯片AE工程师,嵌入式开发工程师,InfoQ签约作者,阿里云专家博主,华为云·云享专家,51CTO专家博主,腾讯云社区优秀共创官。

评论

发布
暂无评论
基于RT-Thread摄像头车牌图像采集系统_开发板_智趣匠_InfoQ写作社区