编程技术分享

分享编程知识,探讨技术创新

0%

简介:安信可小安派-CAM-U核心板,可接入100w像素的USB摄像头

好的,作为一名高级嵌入式软件开发工程师,我将针对安信可小安派-CAM-U核心板,设计一个可靠、高效、可扩展的嵌入式系统平台,并详细阐述其代码架构和实现细节。由于篇幅限制,3000行代码无法全部在此展示,但我会提供核心模块的C代码示例,并详细描述整个系统的架构和实现思路,确保内容详实且具有实践指导意义。
关注微信公众号,提前获取相关推文

项目背景与需求分析

项目背景:

安信可小安派-CAM-U核心板是一款基于高性能处理器的嵌入式开发板,集成了Wi-Fi/蓝牙模块,并支持接入100万像素的USB摄像头。这为我们构建各种图像相关的嵌入式应用提供了硬件基础,例如:

  • 智能监控系统: 实时视频监控、移动侦测、报警推送。
  • 图像识别应用: 人脸识别、物体识别、二维码识别等。
  • 工业视觉检测: 产品缺陷检测、尺寸测量等。
  • 物联网相机: 远程图像采集、数据传输。

需求分析:

基于以上应用场景,我们提炼出以下核心需求:

  1. 可靠性: 系统必须稳定可靠运行,保证长时间无故障工作,尤其是在监控等关键应用中。
  2. 高效性: 系统需要高效处理图像数据,保证实时性,降低延迟。
  3. 可扩展性: 系统架构需要具有良好的可扩展性,方便后续功能增加和升级,例如支持更高分辨率摄像头、增加新的图像处理算法、接入云平台等。
  4. 实时性: 对于监控和视觉检测等应用,实时性至关重要,需要确保图像采集、处理和传输的低延迟。
  5. 低功耗: 嵌入式设备通常对功耗敏感,需要在保证性能的同时,尽可能降低功耗。
  6. 易维护性: 代码结构清晰,模块化设计,方便后期维护和升级。

系统架构设计

为了满足以上需求,我们采用分层模块化的架构设计,将系统划分为多个独立的模块,每个模块负责特定的功能,模块之间通过清晰的接口进行通信。这种架构具有以下优点:

  • 高内聚低耦合: 模块内部功能高度相关,模块之间依赖性低,易于维护和修改。
  • 可重用性: 模块可以独立开发和测试,并在不同项目中重用。
  • 可扩展性: 新增功能可以通过添加新模块或修改现有模块来实现,对整体架构影响小。
  • 易于测试: 模块化设计方便进行单元测试和集成测试,提高系统质量。

系统架构图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
+---------------------+
| 应用层 (Application Layer) |
| (监控应用, 图像识别应用等) |
+---------------------+
|
| 应用接口 (Application Interface)
V
+---------------------+
| 服务层 (Service Layer) |
| (图像处理, 网络通信, 存储管理) |
+---------------------+
|
| 服务接口 (Service Interface)
V
+---------------------+
| 驱动层 (Driver Layer) |
| (摄像头驱动, USB驱动, Wi-Fi驱动, GPIO驱动) |
+---------------------+
|
| 硬件抽象层接口 (HAL Interface)
V
+---------------------+
| 硬件抽象层 (HAL Layer) |
| (底层硬件操作, 寄存器访问) |
+---------------------+
|
| 硬件平台 (Hardware Platform)
V
+---------------------+
| 安信可小安派-CAM-U核心板 |
+---------------------+

各层功能详细说明:

  1. 硬件抽象层 (HAL - Hardware Abstraction Layer):

    • 功能: 封装底层硬件操作,提供统一的硬件访问接口,屏蔽硬件平台的差异性。
    • 模块: GPIO HAL, UART HAL, SPI HAL, I2C HAL, USB HAL, Camera HAL 等。
    • 优点: 上层驱动和应用代码无需关心具体的硬件细节,方便代码移植和维护。
  2. 驱动层 (Driver Layer):

    • 功能: 驱动硬件设备工作,向上层服务层提供设备控制接口。
    • 模块: 摄像头驱动 (USB Camera Driver), USB Host驱动 (USB Host Driver), Wi-Fi驱动 (Wi-Fi Driver), GPIO驱动 (GPIO Driver) 等。
    • 实现: 基于HAL层提供的接口,实现具体硬件设备的驱动逻辑。
  3. 服务层 (Service Layer):

    • 功能: 提供系统核心服务,例如图像处理、网络通信、存储管理、配置管理等。
    • 模块:
      • 图像处理模块 (Image Processing Module): 图像采集、图像预处理 (去噪、增强)、图像分析 (目标检测、人脸识别)、图像编码 (JPEG, H.264) 等。
      • 网络通信模块 (Network Communication Module): Wi-Fi连接管理、TCP/IP协议栈、HTTP/MQTT协议支持、数据传输等。
      • 存储管理模块 (Storage Management Module): 文件系统管理、SD卡/Flash存储操作 (可选,如果需要本地存储)。
      • 配置管理模块 (Configuration Management Module): 系统配置参数管理、配置文件解析、用户配置界面等。
      • 日志管理模块 (Log Management Module): 系统日志记录、错误信息输出、调试信息打印等。
    • 优点: 将核心功能模块化,方便功能扩展和维护,提高代码复用率。
  4. 应用层 (Application Layer):

    • 功能: 实现具体的应用逻辑,例如监控应用、图像识别应用等。
    • 模块: 根据具体应用场景定制开发,例如:
      • 监控应用模块 (Surveillance Application Module): 视频采集、实时编码、网络推流、移动侦测、报警处理等。
      • 图像识别应用模块 (Image Recognition Application Module): 图像采集、预处理、特征提取、模型推理、结果输出等。
    • 实现: 基于服务层提供的接口,构建具体的应用功能。

技术选型与实践验证

为了确保系统的可靠性、高效性和可扩展性,我们在项目中采用了以下技术和方法,并都经过了实践验证:

  1. 操作系统: FreeRTOS (可选)

    • 理由: FreeRTOS 是一个轻量级的实时操作系统,非常适合资源受限的嵌入式系统。它可以提供任务调度、同步机制、内存管理等功能,提高系统的实时性和并发性。
    • 实践验证: FreeRTOS 在众多嵌入式项目中得到广泛应用,其稳定性、可靠性和效率都得到了验证。在本项目中,如果需要实现更复杂的并发任务管理,可以考虑引入FreeRTOS。对于简单的应用,也可以采用裸机开发方式。
  2. 编程语言: C语言

    • 理由: C语言是嵌入式系统开发的首选语言,具有高效、灵活、可移植性强等优点。
    • 实践验证: C语言在嵌入式领域拥有成熟的生态系统和丰富的库支持,开发者社区庞大,学习资源丰富。
  3. USB摄像头驱动: UVC (USB Video Class) 驱动

    • 理由: UVC 是一种通用的USB视频设备类标准,大多数USB摄像头都遵循UVC协议。采用UVC驱动可以简化摄像头驱动开发,提高兼容性。
    • 实践验证: Linux 和许多嵌入式操作系统都内置了UVC驱动,可以直接使用,无需从零开始开发。
  4. 网络协议栈: lwIP (lightweight IP)

    • 理由: lwIP 是一个轻量级的TCP/IP协议栈,专为嵌入式系统设计,资源占用小,效率高。
    • 实践验证: lwIP 在嵌入式领域应用广泛,其性能和可靠性得到了验证。
  5. 图像处理库: OpenCV (可选) / 自研

    • 理由: OpenCV 是一个强大的开源计算机视觉库,提供了丰富的图像处理和计算机视觉算法。如果需要复杂的图像处理功能,可以考虑移植 OpenCV 到嵌入式平台。对于简单的图像处理任务,可以考虑自研轻量级的图像处理算法,以减少资源消耗。
    • 实践验证: OpenCV 在PC端和部分嵌入式平台都有良好的支持,但移植到资源受限的嵌入式平台需要考虑性能和资源优化。自研算法可以根据实际需求进行定制,更加灵活高效。
  6. 代码管理: Git

    • 理由: Git 是目前最流行的版本控制系统,可以有效地管理代码版本,方便团队协作,追踪代码修改历史。
    • 实践验证: Git 在软件开发领域已经成为标准工具,其高效性、可靠性和易用性都得到了广泛认可。
  7. 开发工具: GCC, GDB, Makefile, IDE (例如 VSCode, Eclipse)

    • 理由: GCC 是常用的开源C编译器,GDB 是调试器,Makefile 用于自动化构建,IDE 提供集成的开发环境。这些工具都是嵌入式开发常用的工具链。
    • 实践验证: 这些工具在嵌入式开发领域经过长期实践,成熟稳定,功能强大。

核心模块C代码示例 (简化版)

由于代码量巨大,这里仅提供部分核心模块的简化版C代码示例,用于说明架构设计和实现思路。

1. HAL层 (GPIO HAL - 示例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// hal_gpio.h
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

typedef enum {
GPIO_PIN_0,
GPIO_PIN_1,
// ... more pins
GPIO_PIN_MAX
} gpio_pin_t;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT
} gpio_mode_t;

typedef enum {
GPIO_LEVEL_LOW,
GPIO_LEVEL_HIGH
} gpio_level_t;

// 初始化 GPIO 引脚
void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode);

// 设置 GPIO 引脚输出电平
void hal_gpio_set_level(gpio_pin_t pin, gpio_level_t level);

// 读取 GPIO 引脚输入电平
gpio_level_t hal_gpio_get_level(gpio_pin_t pin);

#endif // HAL_GPIO_H

// hal_gpio.c (平台相关实现)
#include "hal_gpio.h"
// ... 平台相关的寄存器定义和头文件

void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode) {
// ... 平台相关的 GPIO 初始化代码,例如配置寄存器
if (mode == GPIO_MODE_OUTPUT) {
// 设置为输出模式
// ...
} else { // GPIO_MODE_INPUT
// 设置为输入模式
// ...
}
}

void hal_gpio_set_level(gpio_pin_t pin, gpio_level_t level) {
// ... 平台相关的 GPIO 输出电平设置代码,例如写寄存器
if (level == GPIO_LEVEL_HIGH) {
// 输出高电平
// ...
} else { // GPIO_LEVEL_LOW
// 输出低电平
// ...
}
}

gpio_level_t hal_gpio_get_level(gpio_pin_t pin) {
// ... 平台相关的 GPIO 输入电平读取代码,例如读寄存器
// ... 返回 GPIO_LEVEL_HIGH 或 GPIO_LEVEL_LOW
return GPIO_LEVEL_LOW; // 示例
}

2. 驱动层 (USB Camera Driver - 示例 - 简化 UVC)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// usb_camera_driver.h
#ifndef USB_CAMERA_DRIVER_H
#define USB_CAMERA_DRIVER_H

#include "hal_usb.h" // 假设 HAL 层提供了 USB 相关接口

typedef struct {
// ... 摄像头设备信息,例如分辨率,帧率等
} camera_dev_t;

// 初始化 USB 摄像头驱动
camera_dev_t* camera_driver_init();

// 启动摄像头采集
int camera_driver_start_capture(camera_dev_t* dev);

// 停止摄像头采集
int camera_driver_stop_capture(camera_dev_t* dev);

// 获取一帧图像数据
unsigned char* camera_driver_get_frame(camera_dev_t* dev, int* frame_size);

// 释放帧缓冲区
void camera_driver_release_frame(camera_dev_t* dev, unsigned char* frame_buffer);

// 反初始化摄像头驱动
void camera_driver_deinit(camera_dev_t* dev);

#endif // USB_CAMERA_DRIVER_H

// usb_camera_driver.c (简化 UVC 驱动逻辑)
#include "usb_camera_driver.h"
#include "hal_usb.h"
// ... 其他必要的头文件,例如内存管理,错误处理等

camera_dev_t* camera_driver_init() {
camera_dev_t* dev = (camera_dev_t*)malloc(sizeof(camera_dev_t));
if (dev == NULL) {
// 内存分配失败处理
return NULL;
}
// ... 初始化摄像头设备,例如枚举 USB 设备,找到摄像头设备
// ... 配置摄像头参数,例如分辨率,帧率等
return dev;
}

int camera_driver_start_capture(camera_dev_t* dev) {
// ... 启动摄像头采集流程,例如发送 UVC 控制命令
return 0; // 成功
}

int camera_driver_stop_capture(camera_dev_t* dev) {
// ... 停止摄像头采集流程,例如发送 UVC 控制命令
return 0; // 成功
}

unsigned char* camera_driver_get_frame(camera_dev_t* dev, int* frame_size) {
// ... 从 USB 端点接收图像数据
// ... 将数据填充到帧缓冲区
unsigned char* frame_buffer = (unsigned char*)malloc(FRAME_BUFFER_SIZE); // 假设定义了 FRAME_BUFFER_SIZE
if (frame_buffer == NULL) {
// 内存分配失败处理
return NULL;
}
// ... 从 USB 端点读取数据到 frame_buffer
*frame_size = actual_frame_size; // 实际帧大小
return frame_buffer;
}

void camera_driver_release_frame(camera_dev_t* dev, unsigned char* frame_buffer) {
if (frame_buffer != NULL) {
free(frame_buffer);
}
}

void camera_driver_deinit(camera_dev_t* dev) {
if (dev != NULL) {
free(dev);
}
// ... 释放摄像头驱动占用的其他资源
}

3. 服务层 (图像处理模块 - 示例 - 灰度化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// image_processing.h
#ifndef IMAGE_PROCESSING_H
#define IMAGE_PROCESSING_H

// 将 RGB 图像转换为灰度图像
unsigned char* image_process_rgb_to_grayscale(unsigned char* rgb_image, int width, int height, int* grayscale_image_size);

#endif // IMAGE_PROCESSING_H

// image_processing.c
#include "image_processing.h"
#include <stdlib.h>

unsigned char* image_process_rgb_to_grayscale(unsigned char* rgb_image, int width, int height, int* grayscale_image_size) {
if (rgb_image == NULL || width <= 0 || height <= 0) {
return NULL;
}
int rgb_size = width * height * 3; // RGB 图像每个像素 3 字节 (R, G, B)
int gray_size = width * height; // 灰度图像每个像素 1 字节
unsigned char* grayscale_image = (unsigned char*)malloc(gray_size);
if (grayscale_image == NULL) {
return NULL;
}

for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int rgb_index = (i * width + j) * 3;
int gray_index = i * width + j;
unsigned char r = rgb_image[rgb_index];
unsigned char g = rgb_image[rgb_index + 1];
unsigned char b = rgb_image[rgb_index + 2];
// 灰度化公式 (常用平均值法)
unsigned char gray = (r + g + b) / 3;
grayscale_image[gray_index] = gray;
}
}
*grayscale_image_size = gray_size;
return grayscale_image;
}

4. 应用层 (监控应用模块 - 示例 - 简易监控)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// surveillance_app.h
#ifndef SURVEILLANCE_APP_H
#define SURVEILLANCE_APP_H

void surveillance_app_init();
void surveillance_app_run();
void surveillance_app_stop();

#endif // SURVEILLANCE_APP_H

// surveillance_app.c
#include "surveillance_app.h"
#include "usb_camera_driver.h"
#include "image_processing.h"
#include "network_module.h" // 假设有网络模块

#include <stdio.h> // for printf
#include <unistd.h> // for sleep

camera_dev_t* camera_dev = NULL;

void surveillance_app_init() {
printf("监控应用初始化...\n");
camera_dev = camera_driver_init();
if (camera_dev == NULL) {
printf("摄像头驱动初始化失败!\n");
// 错误处理
return;
}
if (camera_driver_start_capture(camera_dev) != 0) {
printf("启动摄像头采集失败!\n");
camera_driver_deinit(camera_dev);
camera_dev = NULL;
return;
}
printf("监控应用初始化完成.\n");
}

void surveillance_app_run() {
printf("监控应用运行中...\n");
while (1) {
int frame_size;
unsigned char* rgb_frame = camera_driver_get_frame(camera_dev, &frame_size);
if (rgb_frame != NULL) {
// 图像处理 (例如灰度化)
int grayscale_size;
unsigned char* grayscale_frame = image_process_rgb_to_grayscale(rgb_frame, 640, 480, &grayscale_size); // 假设 640x480 分辨率
if (grayscale_frame != NULL) {
// 网络传输 (例如发送灰度图像数据)
network_module_send_data(grayscale_frame, grayscale_size); // 假设有网络模块发送数据函数
free(grayscale_frame);
}
camera_driver_release_frame(camera_dev, rgb_frame);
} else {
printf("获取摄像头帧数据失败!\n");
}
sleep(0.1); // 控制帧率,例如 10 FPS
}
}

void surveillance_app_stop() {
printf("监控应用停止...\n");
if (camera_dev != NULL) {
camera_driver_stop_capture(camera_dev);
camera_driver_deinit(camera_dev);
camera_dev = NULL;
}
printf("监控应用已停止.\n");
}

代码说明:

  • HAL层示例 (hal_gpio.c/h): 展示了 GPIO HAL 的接口定义和平台相关的实现框架,实际需要根据具体的硬件平台进行寄存器操作。
  • 摄像头驱动示例 (usb_camera_driver.c/h): 简化了 UVC 驱动的逻辑,主要展示了初始化、启动采集、获取帧数据、释放帧数据等核心接口。实际的 UVC 驱动会更复杂,需要处理 UVC 协议的各种控制命令和数据传输。
  • 图像处理示例 (image_processing.c/h): 提供了一个简单的 RGB 转灰度图像的函数,作为图像处理模块的示例。实际的图像处理模块可以根据需求添加更多算法。
  • 监控应用示例 (surveillance_app.c/h): 展示了一个简易的监控应用框架,包含了摄像头初始化、采集、图像处理 (灰度化)、网络传输 (假设有网络模块),并循环运行。实际的监控应用会更加复杂,例如需要移动侦测、报警处理、用户界面等功能。

系统开发流程

  1. 需求细化与功能分解: 详细分析应用需求,将功能分解为更小的可管理模块,明确每个模块的输入、输出和功能。
  2. 接口设计: 定义模块之间的接口,包括函数接口、数据结构、通信协议等。接口设计要清晰、简洁、易于使用。
  3. 模块开发与单元测试: 按照模块划分,并行开发各个模块。在模块开发完成后,进行单元测试,确保每个模块的功能正确性。
  4. 模块集成与集成测试: 将各个模块集成起来,进行集成测试,验证模块之间的协同工作是否正常,接口是否正确。
  5. 系统测试: 进行全面的系统测试,包括功能测试、性能测试、可靠性测试、稳定性测试等,验证系统是否满足所有需求。
  6. 维护与升级: 系统发布后,进行维护和升级,修复bug,增加新功能,优化性能。

测试与验证

测试是保证系统质量的关键环节。我们需要进行多层次、多角度的测试,包括:

  • 单元测试: 针对每个模块进行独立测试,验证模块功能的正确性。可以使用 C 语言的单元测试框架,例如 cmockaUnity
  • 集成测试: 测试模块之间的接口和协同工作,验证模块集成后的功能是否正常。
  • 系统测试: 对整个系统进行全面的功能测试、性能测试、压力测试、可靠性测试等。
  • 用户场景测试: 模拟实际用户使用场景进行测试,例如长时间运行测试、异常情况测试等。

维护与升级

  • 日志记录: 完善的日志系统可以帮助快速定位和解决问题。在关键模块和关键路径上添加日志输出,记录系统运行状态和错误信息。
  • 错误处理机制: 设计健壮的错误处理机制,避免程序崩溃。对于可恢复的错误,进行重试或降级处理;对于不可恢复的错误,进行安全退出并记录错误信息。
  • 固件升级: 支持固件在线升级 (OTA - Over-The-Air),方便用户升级系统,修复bug,增加新功能。

总结

本文详细介绍了基于安信可小安派-CAM-U核心板的嵌入式系统平台架构设计和实现思路。通过分层模块化的架构、实践验证的技术选型、以及完善的开发流程和测试方法,我们可以构建一个可靠、高效、可扩展的嵌入式系统平台,满足各种图像相关的应用需求。 虽然代码示例只是简化版,但希望能帮助您理解整个系统的架构和实现框架。 在实际项目中,需要根据具体需求进行更详细的设计和开发,并进行充分的测试和验证,才能最终交付高质量的嵌入式产品。

欢迎关注我的其它发布渠道