software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,324 @@
/*
* 自然写智能点阵笔嵌入式固件软件 V1.0
* camera_driver.c - CMOS摄像头传感器驱动
*
* 功能说明:
* 1. CMOS图像传感器SPI通信驱动
* 2. 传感器寄存器配置(曝光、增益、帧率)
* 3. 图像采集触发与数据读取
* 4. 传感器电源管理(开/关/低功耗)
* 5. 自检与故障检测
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal_spi.h"
#include "hal_gpio.h"
/* ========== 传感器寄存器地址 ========== */
/* 芯片ID寄存器(只读) */
#define REG_CHIP_ID 0x00
/* 系统控制寄存器 */
#define REG_SYS_CTRL 0x01
#define SYS_CTRL_RESET 0x80 /* 软复位 */
#define SYS_CTRL_SLEEP 0x40 /* 睡眠模式 */
#define SYS_CTRL_ENABLE 0x01 /* 使能采集 */
/* 曝光时间寄存器(高/低字节) */
#define REG_EXPOSURE_H 0x02
#define REG_EXPOSURE_L 0x03
/* 模拟增益寄存器 */
#define REG_GAIN 0x04
/* 帧率控制寄存器 */
#define REG_FRAME_RATE 0x05
/* 像素数据起始寄存器(读取时自动递增) */
#define REG_PIXEL_DATA 0x10
/* 帧就绪状态位 */
#define REG_STATUS 0x0F
#define STATUS_FRAME_READY 0x01
/* 预期芯片ID值 */
#define EXPECTED_CHIP_ID 0xA5
/* ========== 传感器模式枚举 ========== */
#define CAMERA_MODE_SINGLE 0 /* 单帧模式 */
#define CAMERA_MODE_CONTINUOUS 1 /* 连续帧模式 */
/* ========== GPIO引脚定义 ========== */
#define GPIO_CAMERA_POWER 12 /* 传感器电源控制引脚 */
#define GPIO_CAMERA_CS 15 /* SPI片选引脚 */
#define GPIO_CAMERA_LED 16 /* 红外LED照明引脚 */
/* ========== SPI通信 ========== */
/* SPI端口号 */
#define CAMERA_SPI_PORT SPI_PORT_1
/* 读寄存器标志位 */
#define SPI_READ_FLAG 0x80
/* ========== 静态变量 ========== */
/* 传感器是否已初始化 */
static bool s_camera_initialized = false;
/* 传感器是否已上电 */
static bool s_camera_powered = false;
/* 当前工作模式 */
static uint8_t s_camera_mode = CAMERA_MODE_SINGLE;
/* ========== SPI底层读写 ========== */
/**
* SPI写单个寄存器
* @param reg_addr 寄存器地址(7位)
* @param value 写入值
*/
static void camera_write_reg(uint8_t reg_addr, uint8_t value) {
uint8_t tx[2];
tx[0] = reg_addr & 0x7F; /* 最高位0=写操作 */
tx[1] = value;
hal_gpio_write(GPIO_CAMERA_CS, 0); /* 拉低CS */
hal_spi_transfer(CAMERA_SPI_PORT, tx, NULL, 2);
hal_gpio_write(GPIO_CAMERA_CS, 1); /* 拉高CS */
}
/**
* SPI读单个寄存器
* @param reg_addr 寄存器地址
* @return 读取的值
*/
static uint8_t camera_read_reg(uint8_t reg_addr) {
uint8_t tx[2], rx[2];
tx[0] = reg_addr | SPI_READ_FLAG; /* 最高位1=读操作 */
tx[1] = 0x00; /* 空字节用于接收数据 */
hal_gpio_write(GPIO_CAMERA_CS, 0);
hal_spi_transfer(CAMERA_SPI_PORT, tx, rx, 2);
hal_gpio_write(GPIO_CAMERA_CS, 1);
return rx[1];
}
/**
* SPI批量读取像素数据
* 使用DMA方式高速读取整帧图像数据
*
* @param buffer 接收缓冲区
* @param length 读取字节数
*/
static void camera_read_pixels(uint8_t *buffer, uint16_t length) {
uint8_t cmd = REG_PIXEL_DATA | SPI_READ_FLAG;
hal_gpio_write(GPIO_CAMERA_CS, 0);
/* 先发送寄存器地址 */
hal_spi_transfer(CAMERA_SPI_PORT, &cmd, NULL, 1);
/* 然后连续读取像素数据 */
hal_spi_receive(CAMERA_SPI_PORT, buffer, length);
hal_gpio_write(GPIO_CAMERA_CS, 1);
}
/* ========== 传感器初始化 ========== */
/**
* 初始化CMOS图像传感器
* 配置GPIO、验证芯片ID、设置初始参数
*
* @return 0成功, -1芯片ID错误, -2通信失败
*/
int camera_driver_init(void) {
/* 配置控制GPIO为输出 */
hal_gpio_config_output(GPIO_CAMERA_POWER);
hal_gpio_config_output(GPIO_CAMERA_CS);
hal_gpio_config_output(GPIO_CAMERA_LED);
/* CS默认高电平(不选中) */
hal_gpio_write(GPIO_CAMERA_CS, 1);
/* 上电 */
hal_gpio_write(GPIO_CAMERA_POWER, 1);
s_camera_powered = true;
/* 等待传感器启动(典型10ms) */
for (volatile int i = 0; i < 100000; i++);
/* 软复位 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_RESET);
for (volatile int i = 0; i < 50000; i++);
/* 验证芯片ID */
uint8_t chip_id = camera_read_reg(REG_CHIP_ID);
if (chip_id != EXPECTED_CHIP_ID) {
s_camera_initialized = false;
return -1;
}
/* 设置默认参数 */
camera_write_reg(REG_EXPOSURE_H, 0x00);
camera_write_reg(REG_EXPOSURE_L, 0x80); /* 曝光值128 */
camera_write_reg(REG_GAIN, 0x40); /* 增益64 */
camera_write_reg(REG_FRAME_RATE, 100); /* 100Hz帧率 */
/* 使能传感器 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_ENABLE);
s_camera_initialized = true;
return 0;
}
/* ========== 参数配置 ========== */
/**
* 设置曝光时间
* @param exposure 曝光值(0-255,映射到传感器实际曝光时间)
*/
void camera_set_exposure(uint8_t exposure) {
if (!s_camera_initialized) return;
camera_write_reg(REG_EXPOSURE_H, 0x00);
camera_write_reg(REG_EXPOSURE_L, exposure);
}
/**
* 设置模拟增益
* @param gain 增益值(0-255
*/
void camera_set_gain(uint8_t gain) {
if (!s_camera_initialized) return;
camera_write_reg(REG_GAIN, gain);
}
/**
* 设置工作模式
* @param mode CAMERA_MODE_SINGLE 或 CAMERA_MODE_CONTINUOUS
*/
void camera_set_mode(uint8_t mode) {
s_camera_mode = mode;
}
/* ========== 图像采集 ========== */
/**
* 触发单帧采集
* 在连续模式下,传感器会自动拍摄
* 在单帧模式下,需要每次手动触发
*/
void camera_trigger_capture(void) {
if (!s_camera_initialized || !s_camera_powered) return;
if (s_camera_mode == CAMERA_MODE_SINGLE) {
/* 单帧模式:写触发位 */
uint8_t ctrl = camera_read_reg(REG_SYS_CTRL);
camera_write_reg(REG_SYS_CTRL, ctrl | 0x02);
}
/* 开启红外LED照明(点阵图案需要红外光照射才能看到) */
hal_gpio_write(GPIO_CAMERA_LED, 1);
}
/**
* 等待帧就绪
* @param timeout_ms 超时毫秒数
* @return true帧已就绪, false超时
*/
bool camera_wait_frame_ready(uint16_t timeout_ms) {
uint16_t elapsed = 0;
while (elapsed < timeout_ms) {
uint8_t status = camera_read_reg(REG_STATUS);
if (status & STATUS_FRAME_READY) {
return true;
}
/* 简单延时 */
for (volatile int i = 0; i < 1000; i++);
elapsed++;
}
return false;
}
/**
* 获取传感器数据寄存器地址(用于DMA配置)
*/
uint32_t camera_get_data_register(void) {
/* 返回SPI数据寄存器的内存映射地址 */
return hal_spi_get_data_addr(CAMERA_SPI_PORT);
}
/* ========== 电源管理 ========== */
/**
* 传感器上电
*/
void camera_power_on(void) {
if (s_camera_powered) return;
hal_gpio_write(GPIO_CAMERA_POWER, 1);
s_camera_powered = true;
/* 等待传感器稳定 */
for (volatile int i = 0; i < 100000; i++);
/* 重新使能 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_ENABLE);
}
/**
* 传感器断电(最低功耗)
*/
void camera_power_off(void) {
if (!s_camera_powered) return;
/* 关闭红外LED */
hal_gpio_write(GPIO_CAMERA_LED, 0);
/* 传感器进入睡眠 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_SLEEP);
/* 切断电源 */
hal_gpio_write(GPIO_CAMERA_POWER, 0);
s_camera_powered = false;
}
/**
* 传感器自检
* 检查SPI通信是否正常、芯片ID是否正确
*
* @return 0正常, -1通信故障, -2芯片ID异常
*/
int camera_self_test(void) {
if (!s_camera_powered) {
return -1;
}
uint8_t chip_id = camera_read_reg(REG_CHIP_ID);
if (chip_id != EXPECTED_CHIP_ID) {
return -2;
}
/* 写读测试:写入一个可写寄存器并读回验证 */
uint8_t test_val = 0x55;
camera_write_reg(REG_GAIN, test_val);
uint8_t read_back = camera_read_reg(REG_GAIN);
if (read_back != test_val) {
return -1;
}
/* 恢复原始增益值 */
camera_write_reg(REG_GAIN, 0x40);
return 0;
}