Skip to content
Go back

智能硬件复习

Published:  at  12:20 AM
阅读时间:31 分钟

智能硬件复习

第一章

信息的主要特征:

传统信息处理手段:处理数据才能获取信息

传统方法特点:

  1. 信息(数据):结构化数据(数值、表格等)
  2. 方法:明确的规则、明确的算法为基础
  3. 鲁棒性:数据要准确、完成、干净
  4. 数据量:小,且领域必须相对固定

传统方法缺点:

  1. 信息(数据):难以处理视频等多媒体数据
  2. 方法:难以构建复杂的算法
  3. 鲁棒性:难以兼容多样性数据
  4. 数据量:难以适应信息量爆炸式的增长

==人工智能三大要素:数据,算法,算力==

AI时代,指人工智能成为社会核心驱动力的时代,也是机器具备学习能力自主决策能力的时代,是数据处理方式变革的时代。

AI的特征:

虚拟技术的关键技术:

信息系统:由人、技术、数据和流程等要素构成的综合系统,用于采集、存储、处理、分析和传播信息,以支持系统的决策、协调、控制和运营。

信息系统的构成因素:人、技术、数据、流程、软件硬件

硬件设备分类练习:

软件分类练习:

image-20250531233107450

智能硬件(Smart Hardware):是指集成计算、感知、通信控制等功能的硬件设备,通常具有一定的自我学习、适应、推理和决策 能力,通过与外部环境或用户的交互,执行预定或自主决策任务

智能硬件通常结合了硬件技术、传感器技术、人工智能和物联网技术等,能够在一定程度上实现智能化的操作或自动化功能。

==智能硬件的六大硬件组成==:

==智能硬件的六大软件组成==:

智能硬件的功能特征


第二章

小型智能硬件的计算需求(处理器特点)

**两类智能硬件常用的计算部件:MCU和SoC

32位MCU的特点:性能强大、外设全面,SoC趋势

32位MCU主流内核:ARM Cortex-M内核RISC-V内核,Tensilica Xtensa内核

SoC的基本分类方法:按照性能进行分类:超高性能,高性能,中等性能,弱性能

总线(Bus)是处理器内部功能模块传输信息的公共通道,传统MCU/SoC总线:

MCU/SoC主流使用AMBA(Advanced Microcontroller Bus Architecture)高级微处理器总线架构

AHB(Advanced High-performance Bus):AHB可以将微控制器(CPU)、高带宽的片上RAM、高带宽的外部 存储器接口、DMA总线控制器, 以及各种AHB接口的控制器等连 接起来,构成一套独立的完整的SoC系统。其是单通道总线,不能并行读写特点:高速,高性能

是否SoC的所有部件都需要高速总线?答:低速外设连接高速总线会拉低系统性能,有低速外设的SoC一般都要有低速总线。

APB(Advanced Peripheral Bus):低功耗精简接口总线,可以连接多种不同低速外设;主要应用在低带宽的外设 上,如GPIO、UART、I2C、WDT等。其是单通道总线,不能并行读写特点:低速、性能相对较弱

AHB与APB对比:

AHB与APB之间不能直接连接,而要用Bridge

其他AMBA架构的总线:AXI(Advanced extensible Interface),ACE(AXI Coherency Extensions),CHI(Coherent Hub Interface)。

image-20250601111617781

按键-SoC-LED控制的代码段:

#define PD4(*((volatile unsigned int*)0x40011404)) // volatile:变量易变化,编译器不要优化,每次都需要重新读取
#define PB5(*((volatile unsigned int*)0x40010C08))

int main() {
    while(1) {
        if(PD4==1) {
            PB5=0;
        }else{
            PB5=1;
        }
    }
}
按键状态PD4==输入==电压PD4==输入==逻辑
按键松开0V低电平(0)
按键按下VCC(3.3V)高电平(1)
PB5输出逻辑PB5==输出==电压LED状态
低电平(0)0V点亮
高电平(1)VCC(3.3V)熄灭

第三章

GPIO(General Purpose Input/Output)具备基本的输入或输出的功能。GPIO的输入功能的特征:输入就是获知外部信号的状态,信号是从外至内的。输入:具备识别外部数字信号的功能。

image-20250601123908241

GPIO的基本控制:

  1. 寄存器访问方式:读取输入电平状态(按位访问方式)
// 举例,如何获取第bit位的值
value = ((someRegister & (1 << bit)) >> bit)
// 以下是一个示例
#define someRegister(*((volatile unsigned int*)0x40011404))
unsigned char inputValue = 0;                      //保存第七位的值
unsigned int temp;
temp = someRegister;
inputValue = (unsigned char)((temp & (1 << 7)) >> 7); //填写此处的内容
  1. 寄存器访问方式:设置输出电平状态(同样是按位访问方式)
#define someRegister(*((volatile unsigned int*)0x40010C08))
// 第bit位设置为1(置位)
someRegister = someRegister | (1<<bit); // 或:someRegister |= (1<<bit)
// eg: 第8位设置为1
someRegister = someRegister |= (1<<8);
// 第bit位设置为0(复位)
someRegister = someRegister & ~(1<<bit); //或:someRegister &= ~(1<<bit)
// eg: 第9位设置为0
someRegister = someRegister &= ~(1<<bit);
  1. API访问方式:设置输出电平状态
#define GPIO_04 4
#define SW2_GPIO GPIO_04
typedef enum gpio_level {
    GPIO_LEVEL_LOW,
    GPIO_LEVEL_HIGH
} gpio_level_t;
gpio_level_t inputValue;
inputValue = uapi_gpio_get_val(SW2_GPIO);
if(inputValue == GPIO_LEVEL_LOW) {⋯⋯}
  1. 引脚复用:MCU或SoC的一个物理引脚在使用时,可以设置成多种外设的功能,该功能可以节约引脚资源,减小芯片体积。
#define SW2_GPIO  GPIO_04
#define LED_GPIO  GPIO_05
static int *keyled_task(const char *arg) {
    unused(arg);
    gpio_level_t inputValue;
    
    uapi_pin_set_mode(SW2_GPIO,PIN_MODE_2);// 设置引脚
    uapi_pin_set_mode(LED_GPIO,PIN_MODE_4);
    
    uapi_gpio_set_dir(SW2_GPIO,GPIO_DIRECTION_INPUT);
    uapi_gpio_set_dir(LED_GPIO,GPIO_DIRECTION_OUTPUT);
    while(1) {
        inputValue = uapi_gpio_get_val(SW2_GPIO);
        if(inputValue == GPIO_LEVEL_LOW) {
            uapi_gpio_set_val(LED_GPIO, GPIO_LEVEL_HIGH);
        }else{
            uapi_gpio_set_val(LED_GPIO,GPIO_LEVEL_LOW);
        }
    }
    return 0;
}
  1. GPIO的输入输出、功能切换(复用)需要设置的。GPIO的是否工作可以受控
errcode_t uapi_gpio_set_dir(pin_t pin, gpio_direction_t dir) // 输入输出
errcode_t uapi_pin_set_mode(pin_t pin, pin_mode_t mode) // 功能切换(复用)
void uapi_gpio_init(void) // 工作状态 
void uapi_gpio_deinit(void)

GPIO的电气特性:

  1. GPIO的上拉/下拉可以受控的。
// 内部上拉/下拉电路的控制:以WS63为例,四种可用模式
typedef enum {
    PIN_PULL_TYPE_DISABLE     = 0,         //悬空,仅用于输入确定电平
    PIN_PULL_TYPE_DOWN        = 1,         //下拉
    PIN_PULL_TYPE_STRONG_UP   = 2,         //强上拉
    PIN_PULL_TYPE_UP          = 3,         //上拉
    PIN_PULL_MAX              = 4          //无效
}pin_pull_t;

上拉/下拉电路仅可用于防止输入悬空,不具有带载能力(一般只能流过mA级别以下的电流)

  1. GPIO的电流驱动能力十分有限,绝大多数MCU/SoC的GPIO的输出模式下的电流在30mA以下,两种电流流向的最大电流能力不同。

==中断的作用:==

MCU/SoC的中断:处理器执行程序的过程中,外部或内部的某些事件触发处理器暂时中断当前执行的任务,转去执行与该事件相关的特定程序,处理完事件后再返回继续原任务的过程

中断的流程如下图:

image-20250601230943268

在程序中使用单一中断的要点

在程序中使用中断应避免的问题:

==电平变化事件:==

中断应用示例:将LED控制示例改写为中断模式

static void gpio_callback_func(pin_t pin, uintptr_t param) {
    //⋯⋯
    inputValue = uapi_gpio_get_val(SW2_GPIO); //进入中断后,还需要判断上升沿或下降沿
    if(inputValue == GPIO_LEVEL_LOW) { //低电平,按键松开了
        uapi_gpio_set_val(LED_GPIO,GPIO_LEVEL_HIGH); //LED灭
    }else{        //高电平,按键按下了
        uapi_gpio_set_val(LED_GPIO,GPIO_LEVEL_LOW);  //LED亮
    }
}

static void *button_task(const char *arg) { 
    //⋯⋯ 				//初始化GPIO、按键和LED初始态等,略
    errcode_tret = uapi_gpio_register_isr_func(SW2_GPIO,GPIO_INTERRUPT_DEDGE,gpio_callback_func);
    if(ret != 0) { 
        uapi_gpio_unregister_isr_func(SW2_GPIO);    
    }
    while(1) {
        uapi_watchdog_kick();  //看门狗,后面会讲
        osal_msleep(2000);     //延时,模拟其他任务占用CPU
    }
}

[!NOTE]

中断的引入,大幅度降低了按键查询对系统资源的占用,降低耦合,提高内聚,简化系统开发

uapi_gpio_set_val(LED_GPIO,GPIO_LEVEL_HIGH)uapi_gpio_set_val(LED_GPIO,GPIO_LEVEL_LOW)两个函数,进行了对硬件的“控制”操作,在其他任务中,应避免对同一硬件的控制操作以防止硬件运行故障。

可以使用互斥锁保证LED控制的唯一性。

Q:若有多个中断事件怎么办?

中断优先级:中断事件被处理的顺序机制。作用:中断优先级用于确保关键性或时间敏感的任务能够得到及时处理。中断涉及到现场保护等机制,每次处理中断都要占用系统资源

中断规则:

eg:当Prio(SW2) >Prio(SW3):fucn2能够被打断,构成中断嵌套,fucn2执行过程中,执行func3,func3执行完,再继续执行func2,即fun3的时效性能够得到保障

以数字信号为主的现代信息系统,在输入/感知阶段就首先将模拟信号转换为数字信号再进行后续的处理。==模拟到数字转换的外设:ADC(Analog-to-Digital Converter,模数转换器)==

==ADC的关键参数:==

==ADC的计算方式:==当分辨率为N时


第四章

信息系统中时间的表示方法:

信息设备(智能硬件设备)的计时实现基础:

常用的稳定的频率信号源:民用信息设备一般使用晶体振荡器作为高精度频率信号源。石英晶体振荡器是一种高度稳定的电子振荡器

信息设备(智能硬件设备)计时系统的主要结构:(按序号为处理顺序)

  1. 晶体振荡器:产生稳定的固定频率的信号
  2. 处理电路:信号形式和幅度达到要求
  3. 内部电路:产生系统时钟,供内部使用;也包括对频率信号的处理,例如调整频率、预分频等
  4. 计数器:对特定频率的信号进行计数,即可得到时间的间隔
  1. 计数器输入频率为32768Hz,计数器进行计数16384次的时间是多少?

    时间 = 1638432768\frac{16384}{32768} = 0.5 秒

  2. 计数器输入频率为240MHz,计数器长度16位,达到最大计数时间是多少?

    • 输入频率:240 MHz = 2.4×10^8^ Hz
    • 计数器位数:16位 → 最大计数值 = 2^16^−1 = 65535(从0开始)
    • 计数次数:从0计数到65535,共 65536 次(含0)
    • 时间 = 计数次数 ÷ 频率
    • 时间 = 65536240×106\frac{65536}{240 × 10^6} ≈ 273.07μs

image-20250602105645353

系统时钟CLK(Clock):

WS63定时器的控制流程:

==定时器系统练习:==

// from RXCCCCCC
#include "timer.h" 
#include "tcxo.h" 
#include "chip_core_irq.h" 
#include "common_def.h" 
#include "soc_osal.h" 
#include "app_init.h" 
 
#define TIMER_INDEX                 1 
#define TIMER_PRIO                  1 
#define TIMER_DELAY_INT             5 
#define TIMER_TASK_PRIO             24 
#define TIMER_TASK_STACK_SIZE       0x1000 
 
uint32_t hour = 0, min = 0, sec = 0; 
timer_handle_t timer_index[1] = { 0 };//存储构建好的相应的定时器句柄 
static uint8_t flag;//记录是否有发生过中断 
 
static void timer_timeout_callback(uintptr_t data)//中断回调函数 
{ 
    uint32_t index = (uint32_t)data;//从data中得到是哪个计时器到点 
    flag=1; 
    uapi_timer_start(timer_index[index],1000000, timer_timeout_callback, index);//重启该计时器 
} 
 
static void *timer_task(const char *arg) 
{ 
    unused(arg);//不使用该参数 
    uapi_timer_init();//计时器初始化 
    uapi_timer_adapter(TIMER_INDEX, TIMER_1_IRQN, TIMER_PRIO);//计时器适应 
    uapi_timer_create(TIMER_INDEX, &timer_index[0]);//计时器创建 
    uapi_timer_start(timer_index[0], 1000000, timer_timeout_callback, 0);//计时器启动 
    while (1) { 
        if(flag){//中断触发过了 
        	sec++; 
        	if (sec >= 60) { 
            	sec = 0; 
            	min++; 
        		if (min >= 60) { 
            		min = 0; 
            		hour++; 
            		if (hour >= 24) {//别忘了小时 
            		hour = 0; 
            		} 
        		} 
    		} 
            osal_printk("%02d:%02d:%02d\r\n", hour,min,sec); 
            flag=0; 
        } 
        osal_msleep(TIMER_DELAY_INT); 
    } 
    uapi_timer_stop(timer_index[0]);//停止计时器,防止持续运行 
    uapi_timer_delete(timer_index[0]);//删除计时器 
    uapi_timer_deinit();//去初始化 
    return NULL; 
} 
 
static void timer_entry(void) { 
    osal_task *task_handle = NULL; 
    osal_kthread_lock(); 
    task_handle = osal_kthread_create((osal_kthread_handler)timer_task, 0, 
    "TimerTask", TIMER_TASK_STACK_SIZE); 
    if (task_handle != NULL) { 
        osal_kthread_set_priority(task_handle, TIMER_TASK_PRIO); 
        osal_kfree(task_handle); 
    } 
    osal_kthread_unlock(); 
}

app_run(timer_entry)

==看门狗(Watchdog):==看门狗定时器是目前最简单且有效的软硬件协同的系统监控机制

Systick:一种为系统提供连续的时间间隔计数的硬件定时器

时间间隔定时器分为:

时间戳计时器:


第五章

时序图:描述电路中信号、事件、时钟等随时间变化行为,特别是多个信号或组件相互作用的时间和顺序。其被广泛用于描述信号的时序关系,例如时钟信号、控制信号、输入输出信号等

image-20250602145319073

[!IMPORTANT]

  • 检测到下降沿,再延迟Δt/2后,需要确认是L(低电平),再开始接收
  • 每隔Δt读取一次并接收1bit,8Δt后共接受8bit,即1Byte
  • 同样,接收完毕后读取到H(高电平)才算接收成功
  • 双方Δt一致即可数据传输

UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,是信息系统最通用、最广泛、最经典的通信方式。特点/基本参数:

I2C通信系统的结构与要点:

I2C通信格式的帧格式:

image-20250602155105804

I2C的连接形式:所有的SDA连在一起,所有的SCL连在一起

I2C的传输形式:半双工通信,靠地址区分Slave,所有的通信(包括读取)都由Master发起

I2C的传输速率:标准模式(Standard Mode)100Kbps、快速模式(Fast Mode)400KBps、增强快速模式(Fast Mode+)1Mbps、高速模式(High Speed Mode)3.4Mbps

I2C与UART的主要不同点:

WS63 I2C的主要API - Master:

errcode_t api_i2c_master_init(i2c_bus_t bus,uint32_t baudrate,uint8_t hscode)
i2c_bus_t bus // 设置使用的I2C,WS63有两组I2C硬件外设,包括I2C_BUS_0和I2C_BUS_1
uint32_t baudrate // I2C总线SCL频率,数值即可,如4000000表示400Kbps
uint8_t hscode // I2C总线中Master的地址,可设定值为[0,7]
errcode_t api_i2c_master_write(i2c_bus_t bus,uint16_t dev_addr,i2c_data_t *data)
uint16_t dev_addr // 通信目标Slave的地址
i2c_data_t *data // 待发送的数据的结构体的指针
     typedef struct i2c_data {
         uint8_t *send_buf;              //发送数据的buffer指针,保存Command(待发送的指令)
         uint32_t send_len;              //发送数据的buffer长度,按照图示为1
         uint8_t *receive_buf;          //接收数据的buffer指针,保存Data
         uint32_t receive_len;          //接收数据的buffer长度,按照图示为2
     } i2c_data_t;
errcode_t api_i2c_master_read(i2c_bus_t bus,uint16_t dev_addr,i2c_data_t *data)

从slave读取的流程

image-20250602160746431

WS63 I2C与外部设备(RTC)通信示例:

I2C引脚复用 -> Master初始化速率 -> 初始化外设 -> …… -> 读外设数据 写外设状态

读取INS5699的时间数据:

ins5699s_time ins5699s_GetTime(void){
    ins5699s_time time;
    uint8_t t_reg;
    t_reg = ins5699s_ReadREG(INS5699S_REG_SEC);
    time.sec = (((t_reg&0x70)>>4)*10)+(t_reg&0x0F);
    t_reg=ins5699s_ReadREG(INS5699S_REG_MIN);
    time.min=(((t_reg&0x70)>>4)*10)+(t_reg&0x0F);
    t_reg=ins5699s_ReadREG(INS5699S_REG_HOUR);
    time.hour=(((t_reg&0x30)>>4)*10)+(t_reg&0x0F);
    t_reg=ins5699s_ReadREG(INS5699S_REG_WEEK);
    //处理星期time.week、日time.day、月time.month、年time.year的数据,略
    return time;
}

芯片中的时间寄存器通常使用 BCD(Binary-Coded Decimal)编码,即每个十进制位用 4 个二进制位来存储

以如下代码为例:

t_reg = ins5699s_ReadREG(INS5699S_REG_SEC);
time.sec = (((t_reg & 0x70) >> 4) * 10) + (t_reg & 0x0F);
  • 读取秒寄存器的值

  • t_reg & 0x70:提取高 3 位(十位的 BCD)

  • >> 4:将其移到低位后乘以 10(得到“十位数”)

  • t_reg & 0x0F:提取低 4 位(个位);

  • 相加后得到十进制秒数。

例如:

t_reg = 0x45   // 二进制 0100 0101
=> ((0x40 >> 4) * 10) + 0x05 = (4 * 10 + 5) = 45

SPI通信系统的特点与结构:

==三种板内通信对比:==

特性UARTI2CSPI
通信方式全双工半双工全双工
引脚使用2根 TX/RX2根 SDA/SCL4根 MISO/MOSISCK/CS
主从模式无主从多主机/多从机单主机/多从机
通信速率~100Kbps~3.4Mbps几十Mbps
设备数量2地址范围内受CS引脚数量限制
协议复杂性简单较复杂较简单
错误检测校验位
设备地址
常见应用设备调试、通信设备、卫星定位设备等传感器、外扩存储、RTC、显示模块等存储设备、音频设备、高速传感器等

第六章

==基于线性电压调节器的功率控制==

image-20250602163139390

==脉冲宽度功率控制==:目前最常见的功率控制方法(没有之一),广泛应用于电源转换、电机驱动、LED调光等领域。

==PWM的占空比(Duty Cycle)的计算:==

例:在PWM为10%的情况下

频率高电平时间低电平时间
1kHz100 μs900 μs
2kHz50 μs450 μs

image-20250602164736438

上图中,ARR(自动重装载寄存器)决定周期时间,CCR(捕获比较寄存器)决定高电平持续时间

发声类输出设备:蜂鸣器(Buzzer),用小功率三极管或MOSFET驱动

动作类输出设备:电机

image-20250602170330943

image-20250602170637666

IB HIB L
IA H刹车正转
IA L反转待机

WS63 PWM的使用流程(应先执行 init)

  1. 配置PWM属性的结构体

    typedef struct pwm_config {
        uint32_t low_time; // 三个时间元素,如low_time,实际上的时间是low_time×T,课程使用的WS63版本的T=12.5ns
        uint32_t high_time;
        uint32_t offset_time;
        uint16_t cycles; // cycles为PWM信号周期数,有效范围[0,32767]
        bool repeat;
    } pwm_config_t;
    // 例如:
    pwm_config_t LEDConfig = {100, 100, 0, 0, true}; 
  2. 设置输出PWM的复用引脚

  3. 开启指定的PWM通道

    • errcode_t uapi_pwm_open(uint8_t channel, const pwm_config_t *cfg)
    • uint8_t channel:PWM通道,有效范围[0, 7]
    • const pwm_config_t *cfg:PWM配置结构体
  4. 设置PWM分组,启动PWM分组

    • errcode_t uapi_pwm_set_group(uint8_t group, const uint8_t *channel_set, uint32_t channel_set_len)
    • uint8_t group:分组ID,有效范围[0, 7]
    • const uint8_t *channel_set:包含有该分组中成员通道的数组
    • uint32_t channel_set_len:该分组中的通道数量
    • errcode_t uapi_pwm_start_group(uint8_t group):启动指定分组

编辑此页面

Next Post
概率论与数理统计公式