0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

单片机常用的九大软件架构盘点

无际单片机编程 来源:无际单片机编程 2024-04-29 16:40 次阅读

可能很多工程师,工作了很多年,都不会有软件架构的概念。 因为我在做研发工程师的第6年,才开始意识到这个东西,在此之前,都是做一些比较简单的项目,一个main函数干到底,架构复杂了反而是累赘。 后面有幸,接触了稍微复杂点的项目,感觉以前水平Hold不住,然后借着项目需求,学习了很多优秀的代码架构,比如以前同事的,一些模组厂的SDK,还有市面上成熟的系统。 说出来可能有点夸张,一个好项目带来的成长,顶你做几年小项目。 在一个工程师从入门到成为高级工程师,都会经历哪些软件架构?

下面给大家盘点一下,每个都提供了简易的架构模型代码,难度循环渐进。

1.线性架构

这是最简单的一种程序设计方法,也就是我们在入门时写的,下面是一个使用C语言编写的线性架构示例:

#include   // 包含51系列单片机寄存器定义


// 延时函数,用于产生一定的延迟
void delay(unsigned int count) {
    unsigned int i;
    while(count--) {
        for(i = 0; i < 120; i++) {}  // 空循环,用于产生延迟
    }
}


void main() {
    // 初始设置P1端口为输出模式,用于控制LED
    P1 = 0xFF;  // 将P1端口设置为高电平,关闭所有LED


    while(1) {  // 无限循环
        P1 = 0x00;  // 将P1端口设置为低电平,点亮所有LED
        delay(500000);  // 调用延时函数,延迟一段时间


        P1 = 0xFF;  // 将P1端口设置为高电平,关闭所有LED
        delay(500000);  // 再次调用延时函数,延迟相同的时间
    }
}
2.模块化架构 模块化架构是一种将程序分解为独立模块的设计方法,每个模块执行特定的任务。 这种架构有助于代码的重用、维护和测试。 下面是一个使用C语言编写的模块化架构示例,该程序模拟了一个简单的交通信号灯控制系统
#include   // 包含51系列单片机的寄存器定义


// 定义信号灯的状态
typedef enum {
    RED_LIGHT,
    YELLOW_LIGHT,
    GREEN_LIGHT
} TrafficLightState;


// 函数声明
void initializeTrafficLight(void);
void setTrafficLight(TrafficLightState state);
void delay(unsigned int milliseconds);


// 信号灯控制主函数
void main(void) {
    initializeTrafficLight();  // 初始化交通信号灯


    while(1) {
        setTrafficLight(RED_LIGHT);
        delay(5000);  // 红灯亮5秒


        setTrafficLight(YELLOW_LIGHT);
        delay(2000);  // 黄灯亮2秒


        setTrafficLight(GREEN_LIGHT);
        delay(5000);  // 绿灯亮5秒
    }
}


// 初始化交通信号灯的函数
void initializeTrafficLight(void) {
    // 这里可以添加初始化代码,比如设置端口方向、默认状态等
    // 假设P1端口连接了信号灯,初始状态为熄灭(高电平)
    P1 = 0xFF;
}


// 设置交通信号灯状态的函数
void setTrafficLight(TrafficLightState state) {
    switch(state) {
        case RED_LIGHT:
            // 设置红灯亮,其他灯灭
            P1 = 0b11100000;  // 假设低电平有效,这里设置P1.0为低电平,其余为高电平
            break;
        case YELLOW_LIGHT:
            // 设置黄灯亮,其他灯灭
            P1 = 0b11011000;  // 设置P1.1为低电平,其余为高电平
            break;
        case GREEN_LIGHT:
            // 设置绿灯亮,其他灯灭
            P1 = 0b11000111;  // 设置P1.2为低电平,其余为高电平
            break;
        default:
            // 默认为熄灭所有灯
            P1 = 0xFF;
            break;
    }
}


// 延时函数,参数是毫秒数
void delay(unsigned int milliseconds) {
    unsigned int delayCount = 0;
    while(milliseconds--) {
        for(delayCount = 0; delayCount < 120; delayCount++) {
            // 空循环,用于产生延时
        }
    }
}

3.层次化架构 层次化架构是一种将系统分解为多个层次的设计方法,每个层次负责不同的功能。

着以下是一个使用C语言编写的层次化架构示例,模拟了一个具有不同权限级别的嵌入式系统

#include   // 包含51系列单片机的寄存器定义


// 定义不同的操作级别
typedef enum {
    LEVEL_USER,
    LEVEL_ADMIN,
    LEVEL_SUPERUSER
} OperationLevel;


// 函数声明
void systemInit(void);
void performOperation(OperationLevel level);
void displayMessage(char* message);


// 系统初始化后的主循环
void main(void) {
    systemInit();  // 系统初始化


    // 模拟用户操作
    performOperation(LEVEL_USER);
    // 模拟管理员操作
    performOperation(LEVEL_ADMIN);
    // 模拟超级用户操作
    performOperation(LEVEL_SUPERUSER);


    while(1) {
        // 主循环可以是空闲循环或者处理其他低优先级任务
    }
}


// 系统初始化函数
void systemInit(void) {
    // 初始化系统资源,如设置端口、中断等
    // 这里省略具体的初始化代码
}


// 执行不同级别操作的函数
void performOperation(OperationLevel level) {
    switch(level) {
        case LEVEL_USER:
          //用户操作具体代码
            break;
        case LEVEL_ADMIN:
          //管理员操作具体代码
            break;
        case LEVEL_SUPERUSER:
           //超级用户操作具体代码
            break;
    }
}


// 显示消息的函数
void displayMessage(char* message) {
    // 这里省略了实际的显示代码,因为单片机通常没有直接的屏幕输出
    // 消息可以通过LED闪烁、串口输出或其他方式展示
    // 假设通过P1端口的LED展示,每个字符对应一个LED闪烁模式
    // 实际应用中,需要根据硬件设计来实现消息的显示
}



4.事件驱动架构

事件驱动架构是一种编程范式,其中程序的执行流程由事件(如用户输入、传感器变化、定时器到期等)触发。 在单片机开发中,事件驱动架构通常用于响应外部硬件中断或软件中断。 以下是一个使用C语言编写的事件驱动架构示例,模拟了一个基于按键输入的LED控制。

#include   // 包含51系列单片机的寄存器定义


// 定义按键和LED的状态
#define KEY_PORT P3  // 假设按键连接在P3端口
#define LED_PORT P2  // 假设LED连接在P2端口


// 函数声明
void delay(unsigned int milliseconds);
bit checkKeyPress(void);  // 返回按键是否被按下的状态(1表示按下,0表示未按下)


// 定时器初始化函数
void timer0Init(void) 
{
    TMOD = 0x01;  // 设置定时器模式寄存器,使用模式1(16位定时器)
    TH0 = 0xFC;   // 设置定时器初值,用于产生定时中断
    TL0 = 0x18;
    ET0 = 1;      // 开启定时器0中断
    EA = 1;       // 开启总中断
    TR0 = 1;      // 启动定时器
}


// 定时器中断服务程序
void timer0_ISR() interrupt 1 
{
    // 定时器溢出后自动重新加载初值,无需手动重置
    // 这里可以放置定时器溢出后需要执行的代码
}


// 按键中断服务程序
bit keyPress_ISR(void) interrupt 2 using 1 
{
    if(KEY_PORT != 0xFF) // 检测是否有按键按下
        {  
        LED_PORT = ~LED_PORT;  // 如果有按键按下,切换LED状态
        delay(20);  // 去抖动延时
        while(KEY_PORT != 0xFF);  // 等待按键释放
        return 1;  // 返回按键已按下
    }
    return 0;  // 如果没有按键按下,返回0
}


// 延时函数,参数是毫秒数
void delay(unsigned int milliseconds) {
    unsigned int i, j;
    for(i = 0; i < milliseconds; i++)
        for(j = 0; j < 1200; j++);  // 空循环,用于产生延时
}


// 主函数
void main(void) 
{
    timer0Init();  // 初始化定时器
    LED_PORT = 0xFF;  // 初始LED熄灭(假设低电平点亮LED)


    while(1) 
    {
        if(checkKeyPress())
        {  // 检查是否有按键按下事件
            // 如果有按键按下,这里可以添加额外的处理代码
        }
    }
}


// 检查按键是否被按下的函数
bit checkKeyPress(void) 
{
    bit keyState = 0;
    // 模拟按键中断触发,实际应用中需要连接硬件中断
    if(1) // 假设按键中断触发
    {  
      keyState = keyPress_ISR();  // 调用按键中断服务程序
    }
    return keyState;  // 返回按键状态
}
事实上,真正的事件型驱动架构,是非常复杂的,我职业生涯的巅峰之作,就是用的事件型驱动架构。

c5f76e4a-0601-11ef-a297-92fbcf53809c.png

5.状态机架构 在单片机开发中,状态机常用于处理复杂的逻辑和事件序列,如用户界面管理、协议解析等。 以下是一个使用C语言编写的有限状态机(FSM)的示例,模拟了一个简单的自动售货机的状态转换。

#include   // 包含51系列单片机的寄存器定义


// 定义自动售货机的状态
typedef enum {
    IDLE,
    COIN_INSERTED,
    PRODUCT_SELECTED,
    DISPENSE,
    CHANGE_RETURNED
} VendingMachineState;


// 定义事件
typedef enum {
    COIN_EVENT,
    PRODUCT_EVENT,
    DISPENSE_EVENT,
    REFUND_EVENT
} VendingMachineEvent;


// 函数声明
void processEvent(VendingMachineEvent event);
void dispenseProduct(void);
void returnChange(void);


// 当前状态
VendingMachineState currentState = IDLE;


// 主函数
void main(void)
{
    // 初始化代码(如果有)
    // ...


    while(1)
    {
        // 假设事件由外部触发,这里使用一个模拟事件
        VendingMachineEvent currentEvent = COIN_EVENT; // 模拟投入硬币事件


        processEvent(currentEvent);  // 处理当前事件
    }
}


// 处理事件的函数
void processEvent(VendingMachineEvent event)
{
    switch(currentState)
    {
        case IDLE:
            if(event == COIN_EVENT)
            {
                // 如果在空闲状态且检测到硬币投入事件,则转换到硬币投入状态
                currentState = COIN_INSERTED;
            }
            break;
        case COIN_INSERTED:
            if(event == PRODUCT_EVENT)
            {
                // 如果在硬币投入状态且用户选择商品,则请求出货
                currentState = PRODUCT_SELECTED;
            }
            break;
        case PRODUCT_SELECTED:
            if(event == DISPENSE_EVENT)
            {
                dispenseProduct();  // 出货商品
                currentState = DISPENSE;
            }
            break;
        case DISPENSE:
            if(event == REFUND_EVENT)
            {
                returnChange();  // 返回找零
                currentState = CHANGE_RETURNED;
            }
            break;
        case CHANGE_RETURNED:
            // 等待下一个循环,返回到IDLE状态
            currentState = IDLE;
            break;
        default:
            // 如果状态非法,重置为IDLE状态
            currentState = IDLE;
            break;
    }
}


// 出货商品的函数
void dispenseProduct(void)
{
    // 这里添加出货逻辑,例如激活电机推出商品
    // 假设P1端口连接了出货电机
    P1 = 0x00;  // 激活电机
    // ... 出货逻辑
    P1 = 0xFF;  // 关闭电机
}


// 返回找零的函数
void returnChange(void)
{
    // 这里添加找零逻辑,例如激活机械臂放置零钱
    // 假设P2端口连接了找零机械臂
    P2 = 0x00;  // 激活机械臂
    // ... 找零逻辑
    P2 = 0xFF;  // 关闭机械臂
}

6.面向对象架构 STM32的库,就是一种面向对象的架构。 不过在单片机由于资源限制,OOP并不像在高级语言中那样常见,但是一些基本概念如封装和抽象仍然可以被应用。

虽然C语言本身并不直接支持面向对象编程,但可以通过结构体和函数指针模拟一些面向对象的特性。 下面是一个简化的示例,展示如何在C语言中模拟面向对象的编程风格,以51单片机为背景,创建一个简单的LED类。

#include 


// 定义一个LED类
typedef struct {
    unsigned char state;  // LED的状态
    unsigned char pin;    // LED连接的引脚
    void (*turnOn)(struct LED*);  // 点亮LED的方法
    void (*turnOff)(struct LED*); // 熄灭LED的方法
} LED;


// LED类的构造函数
void LED_Init(LED* led, unsigned char pin) {
    led->state = 0;  // 默认状态为熄灭
    led->pin = pin;   // 设置LED连接的引脚
}


// 点亮LED的方法
void LED_TurnOn(LED* led) {
    // 根据引脚状态点亮LED
    if(led->pin < 8) {
        P0 |= (1 << led->pin);  // 假设P0.0到P0.7连接了8个LED
    } else {
        P1 &= ~(1 << (led->pin - 8));  // 假设P1.0到P1.7连接了另外8个LED
    }
    led->state = 1;  // 更新状态为点亮
}


// 熄灭LED的方法
void LED_TurnOff(LED* led) {
    // 根据引脚状态熄灭LED
    if(led->pin < 8) {
        P0 &= ~(1 << led->pin);  // 熄灭P0上的LED
    } else {
        P1 |= (1 << (led->pin - 8));  // 熄灭P1上的LED
    }
    led->state = 0;  // 更新状态为熄灭
}


// 主函数
void main(void) {
    LED myLed;  // 创建一个LED对象
    LED_Init(&myLed, 3);  // 初始化LED对象,连接在P0.3


    // 给LED对象绑定方法
    myLed.turnOn = LED_TurnOn;
    myLed.turnOff = LED_TurnOff;


    // 使用面向对象的风格控制LED
    while(1) {
        myLed.turnOn(&myLed);  // 点亮LED
        // 延时
        myLed.turnOff(&myLed); // 熄灭LED
        // 延时
    }
}
这段代码定义了一个结构体LED,模拟面向对象中的“类。 这个示例仅用于展示如何在C语言中模拟面向对象的风格,并没有使用真正的面向对象编程语言的特性,如继承和多态,不过对于单片机的应用,足以。 7.基于任务的架构 这种我最喜欢用,结构,逻辑清晰,每个任务都能灵活调度。

基于任务的架构是将程序分解为独立的任务,每个任务执行特定的工作。

在单片机开发中,如果没有使用实时操作系统,我们可以通过编写一个简单的轮询调度器来模拟基于任务的架构。

以下是一个使用C语言编写的基于任务的架构的示例,该程序在51单片机上实现。

为了简化,我们将使用一个简单的轮询调度器来在两个任务之间切换:一个是按键扫描任务,另一个是LED闪烁任务。

#include 


// 假设P1.0是LED输出
sbit LED = P1^0;


// 全局变量,用于记录系统Tick
unsigned int systemTick = 0;


// 任务函数声明
void taskLEDBlink(void);
void taskKeyScan(void);


// 定时器0中断服务程序,用于产生Tick
void timer0_ISR() interrupt 1 using 1 
{
    // 定时器溢出后自动重新加载初值,无需手动重置
    systemTick++;  // 更新系统Tick计数器
}


// 任务调度器,主函数中调用,负责任务轮询
void taskScheduler(void) 
{
    // 检查系统Tick,决定是否执行任务
    // 例如,如果我们需要每1000个Tick执行一次LED闪烁任务
    if (systemTick % 1000 == 0) 
    {
       taskLEDBlink();
    }
    // 如果有按键任务,可以类似地检查Tick并执行
    if (systemTick % 10 == 0) 
    {
       taskKeyScan();
    }
}


// LED闪烁任务
void taskLEDBlink(void) 
{
    static bit ledState = 0;  // 用于记录LED的当前状态
    ledState = !ledState;  // 切换LED状态
    LED = ledState;         // 更新LED硬件状态
}


// 按键扫描任务(示例中省略具体实现)
void taskKeyScan(void) 
{
    // 按键扫描逻辑
}


// 主函数
void main(void) 
{
    // 初始化LED状态
    LED = 0;


    // 定时器0初始化设置
    TMOD &= 0xF0;  // 设置定时器模式寄存器,使用模式1(16位定时器/计数器)
    TH0 = 0x4C;     // 设置定时器初值,产生定时中断(定时周期取决于系统时钟频率)
    TL0 = 0x00;
    ET0 = 1;        // 允许定时器0中断
    EA = 1;         // 允许中断
    TR0 = 1;        // 启动定时器0


    while(1) 
    {
        taskScheduler();  // 调用任务调度器
    }
}
这里只是举个简单的例子,这个代码示例,比较适合51和stm8这种资源非常少的单片机。

8.代理架构 这个大家或许比较少听到过,但在稍微复杂的项目中,是非常常用的。

在代理架构中,每个代理(Agent)都是一个独立的实体,它封装了特定的决策逻辑和数据,并与其他代理进行交互。

在实际项目中,需要创建多个独立的任务或模块,每个模块负责特定的功能,并通过某种机制(如消息队列、事件触发等)进行通信。

这种方式可以大大提高程序可扩展性和可移植性。

以下是一个LED和按键代理的简化模型。

#include   // 包含51系列单片机的寄存器定义


// 假设P3.5是按键输入,P1.0是LED输出
sbit KEY = P3^5;
sbit LED = P1^0;


typedef struct 
{
    unsigned char pin;    // 代理关联的引脚
    void (*action)(void); // 代理的行为函数
} Agent;


// 按键代理的行为函数声明
void keyAction(void);
// LED代理的行为函数声明
void ledAction(void);


// 代理数组,存储所有代理的行为和关联的引脚
Agent agents[] = 
{
    {5, keyAction},  // 按键代理,关联P3.5
    {0, ledAction}   // LED代理,关联P1.0
};


// 按键代理的行为函数
void keyAction(void) 
{
    if(KEY == 0) // 检测按键是否被按下
        {  
        LED = !LED;   // 如果按键被按下,切换LED状态
        while(KEY == 0);  // 等待按键释放
    }
}


// LED代理的行为函数
void ledAction(void) 
{
    static unsigned int toggleCounter = 0;
    toggleCounter++;
    if(toggleCounter == 500)  // 假设每500个时钟周期切换一次LED
        { 
        LED = !LED;               // 切换LED状态
        toggleCounter = 0;        // 重置计数器
    }
}


// 主函数
void main(void) 
{
    unsigned char agentIndex;
    // 主循环
    while(1) 
    {
        for(agentIndex = 0; agentIndex < sizeof(agents) / sizeof(agents[0]); agentIndex++) 
        {
            // 调用每个代理的行为函数
            (*agents[agentIndex].action)(); // 注意函数指针的调用方式
        }
    }
}

9.组件化架构 组件化架构是一种将软件系统分解为独立、可重用组件的方法。

将程序分割成负责特定任务的模块,如LED控制、按键处理、传感器读数等。

每个组件可以独立开发和测试,然后被组合在一起形成完整的系统。

以下是一个简化的组件化架构示例,模拟了一个单片机系统中的LED控制和按键输入处理两个组件。

为了简化,组件间的通信将通过直接函数调用来模拟。

#include   // 包含51系列单片机的寄存器定义


// 定义组件结构体
typedef struct 
{
    void (*init)(void);      // 组件初始化函数
    void (*task)(void);       // 组件任务函数
} Component;


// 假设P3.5是按键输入,P1.0是LED输出
sbit KEY = P3^5;
sbit LED = P1^0;


// LED组件
void LED_Init(void) 
{
    LED = 0;  // 初始化LED状态为关闭
}


void LED_Task(void) 
{
    static unsigned int toggleCounter = 0;
    toggleCounter++;
    if (toggleCounter >= 1000) // 假设每1000个时钟周期切换一次LED
    {  
        LED = !LED;                // 切换LED状态
        toggleCounter = 0;         // 重置计数器
    }
}


// 按键组件
void KEY_Init(void) 
{
    // 按键初始化代码
}


void KEY_Task(void) 
{
    if (KEY == 0) // 检测按键是否被按下
    {  
       LED = !LED;  // 如果按键被按下,切换LED状态
       while(KEY == 0);  // 等待按键释放
    }
}


// 组件数组,存储系统中所有组件的初始化和任务函数
Component components[] = 
{
    {LED_Init, LED_Task},
    {KEY_Init, KEY_Task}
};


// 系统初始化函数,调用所有组件的初始化函数
void System_Init(void) 
{
    unsigned char componentIndex;
    for (componentIndex = 0; componentIndex < sizeof(components) / sizeof(components[0]); componentIndex++) 
    {
        components[componentIndex].init();
    }
}


// 主循环,调用所有组件的任务函数
void main(void) 
{
    System_Init();  // 系统初始化
    while(1) 
    {
        unsigned char componentIndex;
        for (componentIndex = 0; componentIndex < sizeof(components) / sizeof(components[0]); componentIndex++)
        {
            components[componentIndex].task();  // 调用组件任务
        }
    }
}
审核编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6037

    文章

    44559

    浏览量

    635496
  • 寄存器
    +关注

    关注

    31

    文章

    5343

    浏览量

    120400
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3593

    浏览量

    129491
  • C语言
    +关注

    关注

    180

    文章

    7605

    浏览量

    136884

原文标题:长文干货预警 | 单片机常用的9种软件架构!

文章出处:【微信号:nanshuqg,微信公众号:无际单片机编程】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    单片机开发中常用的三种软件架构

    嵌入式系统的软件架构是构建可靠嵌入式应用程序的关键。本文将探讨单片机开发中常用的三种软件架构:分
    发表于 09-13 09:25 3308次阅读

    单片机常用软件

    单片机常用软件
    发表于 12-25 18:52

    51单片机常用软件

    51单片机常用软件
    发表于 12-25 18:54

    单片机常用辅助软件

    单片机常用的辅助软件
    发表于 12-05 23:00

    单片机常用软件下载分享

    单片机常用软件在附件内
    发表于 07-08 13:11

    单片机常用辅助软件自取!

    51单片机常用辅助开发工具软件免费下载!51Hex_Bin、51波特率初值设定、51定时器计算、lcd汉字取模软件单片机小精灵
    发表于 03-24 22:44

    概述常用单片机软件架构

    一、概述常用单片机软件架构大体分三种:1. 前后台顺序执行程序2. 时间片轮询法3. 操作系统二、前后台顺序执行程序所谓的前台,就是主动去判断处理某个事务,这个是主循环里要做的事,也就
    发表于 11-22 06:57

    单片机系统常用软件抗干扰措施

    单片机系统常用软件抗干扰措施:可靠性设计是一项系统工程,单片机系统的可靠性必须从软件、硬件以及结构设计等方面全面考虑。硬件系统的可靠性设计是单片机
    发表于 04-28 11:39 18次下载

    常用单片机介绍

    常用单片机介绍 单片机种类繁多,但是一般常用的有以下几种:    ATMEL公司的AVR单片机,是增强型RISC内
    发表于 03-18 15:30 2094次阅读

    单片机教程:单片机数据传递类指令

    单片机教程:单片机数据传递类指令 单片机数据传递类指令 (3)以直接地址为目的操作数的指令 MOV direct,A 例: MOV 20H,A
    发表于 05-15 23:03 858次阅读
    <b class='flag-5'>单片机</b>教程<b class='flag-5'>九</b>:<b class='flag-5'>单片机</b>数据传递类指令

    单片机常用算法设计

    单片机常用算法归纳
    发表于 04-05 14:01 5次下载

    单片机学习和开发常用软件合集免费下载

    本文档的主要内容详细介绍的是单片机学习和开发常用软件合集免费下载包括了:串口调试助手,图片取模软件,文字取模软件,51波特率初值设定,ST
    发表于 03-27 08:00 6次下载
    <b class='flag-5'>单片机</b>学习和开发<b class='flag-5'>常用</b>的<b class='flag-5'>软件</b>合集免费下载

    单片机开发会用到的常用软件合集

    本文档的主要内容详细介绍的是单片机开发会用到的常用软件合集 串口调试助手、网络调试助手、字库制作软件、文字取模软件等,都在里面。
    发表于 01-08 08:00 7次下载
    <b class='flag-5'>单片机</b>开发会用到的<b class='flag-5'>常用软件</b>合集

    分享:单片机常用术语

    分享:单片机常用术语
    发表于 02-10 11:11 6次下载
    分享:<b class='flag-5'>单片机</b><b class='flag-5'>常用</b>术语

    arm架构单片机有哪些 arm单片机选型

    一些常见的ARM架构单片机包括:   1. STM32系列:主要包括Cortex-M0, Cortex-M3, Cortex-M4等内核的单片机,是比较常用的高性价比的ARM
    发表于 03-23 15:47 6607次阅读