当前位置: 首页 > news >正文

RT-Thread基于AT32单片机的CAN应用

1 硬件电路

2 RT-Thread驱动配置

RT-Studio中没有CAN相关的图形配置,需要手动修改board.h。在board.h的末尾,增加相关的BSP配置。

#define RT_CAN_USING_HDR
#define BSP_USING_CAN1

3 IO配置

at32_msp.c中的IO配置是PB9和PB10,掌上实验室V9实际采用的是PD0和PD1,需要修改CAN1相关的IO配置代码。

IO配置代码可以采用AT32_workbench生成,如下图所示。

at32a403a_wk_config.c中找到相关代码,修改RT-Studio中的at32_msp.c的相关代码,如下所示:

void at32_msp_can_init(void *instance)
{
#if defined (BSP_USING_CAN1) || defined (BSP_USING_CAN2)gpio_init_type gpio_init_struct;can_type *can_x = (can_type *)instance;gpio_default_para_init(&gpio_init_struct);gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
#ifdef BSP_USING_CAN1if(CAN1 == can_x){crm_periph_clock_enable(CRM_CAN1_PERIPH_CLOCK, TRUE);
//        crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
//        crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
//
//        gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
//        gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
//        gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
//        gpio_init_struct.gpio_pins = GPIO_PINS_9;
//        gpio_init(GPIOB, &gpio_init_struct);
//        gpio_pin_remap_config(CAN1_GMUX_0010, TRUE);
//
//        gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
//        gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
//        gpio_init_struct.gpio_pins = GPIO_PINS_8;
//        gpio_init(GPIOB, &gpio_init_struct);crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);/* configure the CAN1 TX pin */gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_mode = GPIO_MODE_MUX;gpio_init_struct.gpio_pins = GPIO_PINS_1;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init(GPIOD, &gpio_init_struct);/* configure the CAN1 RX pin */gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_pins = GPIO_PINS_0;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init(GPIOD, &gpio_init_struct);/* GPIO PIN remap */gpio_pin_remap_config(CAN1_GMUX_0011, TRUE);}
#endif
#ifdef BSP_USING_CAN2if(CAN2 == can_x){crm_periph_clock_enable(CRM_CAN2_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);gpio_init_struct.gpio_mode = GPIO_MODE_MUX;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_6;gpio_init(GPIOB, &gpio_init_struct);gpio_pin_remap_config(CAN2_GMUX_0001, TRUE);gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_5;gpio_init(GPIOB, &gpio_init_struct);}
#endif
#endif
}void at32_msp_emac_init(void *instance)
{
#if defined (BSP_USING_EMAC)gpio_init_type gpio_init_struct;crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);gpio_pin_remap_config(EMAC_MUX, TRUE);gpio_default_para_init(&gpio_init_struct);gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;gpio_init_struct.gpio_mode = GPIO_MODE_MUX;gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_2;gpio_init(GPIOA, &gpio_init_struct);gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_12 | GPIO_PINS_13;gpio_init(GPIOB, &gpio_init_struct);gpio_init_struct.gpio_pins = GPIO_PINS_1;gpio_init(GPIOC, &gpio_init_struct);gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_1;gpio_init(GPIOA, &gpio_init_struct);gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;gpio_init_struct.gpio_pull = GPIO_PULL_NONE;gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10;gpio_init(GPIOD, &gpio_init_struct);
#endif
}

4 时钟配置

drv_can.c中给出了can的bitrate配置代码,如下所示:

#ifdef SOC_SERIES_AT32F403A
/* attention !!! baud calculation example: apbclk / ((ss + bs1 + bs2) * brp), ep: 120 / ((1 + 8 + 3) * 10) = 1MHz*/
/* attention !!! default apbclk 120 mhz */
static const struct at32_baud_rate can_baud_rate_tab[] =
{{CAN1MBaud,   {10 , CAN_RSAW_3TQ, CAN_BTS1_8TQ,  CAN_BTS2_3TQ}},{CAN800kBaud, {15 , CAN_RSAW_2TQ, CAN_BTS1_7TQ,  CAN_BTS2_2TQ}},{CAN500kBaud, {20 , CAN_RSAW_2TQ, CAN_BTS1_9TQ,  CAN_BTS2_2TQ}},{CAN250kBaud, {40 , CAN_RSAW_2TQ, CAN_BTS1_9TQ,  CAN_BTS2_2TQ}},{CAN125kBaud, {80 , CAN_RSAW_2TQ, CAN_BTS1_9TQ,  CAN_BTS2_2TQ}},{CAN100kBaud, {75 , CAN_RSAW_2TQ, CAN_BTS1_13TQ, CAN_BTS2_2TQ}},{CAN50kBaud,  {150, CAN_RSAW_2TQ, CAN_BTS1_13TQ, CAN_BTS2_2TQ}},{CAN20kBaud,  {375, CAN_RSAW_2TQ, CAN_BTS1_13TQ, CAN_BTS2_2TQ}},{CAN10kBaud,  {750, CAN_RSAW_2TQ, CAN_BTS1_13TQ, CAN_BTS2_2TQ}}
};

这里要特别注意的是,所有计算是基于apbclk=120MHz。要确认RT-Studio生成的代码的时钟正确,否则需重新配置时钟或修改at32_baud_rate can_baud_rate_tab表格内容。

5 RT-Thread应用示例

#include <rtthread.h>
#include "rtdevice.h"#ifdef RT_USING_CAN#define CAN_DEV_NAME       "can1"      /* CAN 设备名称 */static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
static rt_device_t can_dev;            /* CAN 设备句柄 */#define THREAD_PRIORITY         25
#define THREAD_STACK_SIZE       512
#define THREAD_TIMESLICE        5static rt_thread_t tid1 = RT_NULL;
static volatile int running = 0;static int data_buf[10];
static uint32_t data_cnt = 0;rt_err_t lp40_recv(uint16_t id, uint8_t *msg)
{if(crc_high_first(msg,6)){}return RT_EOK;}/* 接收数据回调函数 */
static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size) {/* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */rt_sem_release(&rx_sem);return RT_EOK;
}static void can_rx_thread(void *parameter) {int i;//rt_err_t res;struct rt_can_msg rxmsg = {0};/* 设置接收回调函数 */rt_device_set_rx_indicate(can_dev, can_rx_call);#ifdef RT_CAN_USING_HDRstruct rt_can_filter_item items[5] = {RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 1, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr 为 - 1 */{0x555, 0, 0, 1, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */};struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 *//* 设置硬件过滤表 */res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);RT_ASSERT(res == RT_EOK);
#endifint rx_count = 0;while (running) {/* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */rxmsg.hdr_index = -1;/* 阻塞等待接收信号量 */if(rt_sem_take(&rx_sem, RT_WAITING_FOREVER)==RT_EOK){/* 从 CAN 读取一帧数据 */rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));/* 打印数据 ID 及内容 */rt_kprintf("recv %ld : id = %d, ide=%d :", ++rx_count, rxmsg.id, rxmsg.ide);for (i = 0; i < rxmsg.len; i++) {rt_kprintf(" %02x", rxmsg.data[i]);}rt_kprintf("\n");}}
}/* 线程 1 的入口函数 */
static void thread1_entry(void *parameter) {struct rt_can_msg msg = {0};int count = 0;msg.id = 0x123;              /* ID 为 0x78 */msg.ide = RT_CAN_STDID;     /* 标准格式 *///msg.ide = RT_CAN_EXTID;     /* 标准格式 */msg.rtr = RT_CAN_DTR;       /* 数据帧 */msg.len = 8;                /* 数据长度为 8 *//* 待发送的 8 字节数据 */msg.data[0] = 0x00;msg.data[1] = 0x11;msg.data[2] = 0x22;msg.data[3] = 0x33;msg.data[4] = 0x44;msg.data[5] = 0x55;msg.data[6] = 0x66;msg.data[7] = 0x77;while(running) {/* 线程 1 采用低优先级运行,一直打印计数值 */rt_kprintf("send %d : id = %d, ide=%d :", ++count, msg.id, msg.ide);for(int i=0;i<msg.len;i++)rt_kprintf(" %02x", msg.data[i]);rt_kprintf("\n");rt_device_write(can_dev, 0, &msg, sizeof(msg));for(int i=0;i<100;i++){rt_thread_mdelay(50);if(!running)break;}}rt_device_close(can_dev);
}int can_sample(int argc, char *argv[]) {rt_err_t res;rt_size_t  size;rt_thread_t thread;char can_name[RT_NAME_MAX];if (argc == 2) {rt_strncpy(can_name, argv[1], RT_NAME_MAX);} else {rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);}if(running){rt_kprintf("can_sample is running, stop it before restart!\n    can_sample_stop\n", can_name);return RT_ERROR;}/* 查找 CAN 设备 */can_dev = rt_device_find(can_name);if (!can_dev) {rt_kprintf("find %s failed!\n", can_name);return RT_ERROR;}running = 1;res = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);/* 以中断接收及发送方式打开 CAN 设备 */res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);/* 初始化 CAN 接收信号量 *//* 设置 CAN 的工作模式为正常工作模式 */res = rt_device_control(can_dev, RT_CAN_CMD_SET_MODE, (void *)RT_CAN_MODE_NORMAL);//res = rt_device_control(can_dev, RT_CAN_CMD_SET_MODE, (void *)RT_CAN_MODE_LOOPBACK);res = rt_device_control(can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN125kBaud);RT_ASSERT(res == RT_EOK);/* 创建数据接收线程 */thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);if (thread != RT_NULL) {rt_thread_startup(thread);} else {rt_kprintf("create can_rx thread failed!\n");}if (size == 0) {rt_kprintf("can dev write data failed!\n");}/* 创建线程 1,名称是 thread1,入口是 thread1_entry*/tid1 = rt_thread_create("thread1",thread1_entry, RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY, THREAD_TIMESLICE);/* 如果获得线程控制块,启动这个线程 */if (tid1 != RT_NULL)rt_thread_startup(tid1);elsert_kprintf("start can send fail\n");return res;
}int can_sample_stop(int argc, char *argv[]) {if(running){running = 0;//rt_sem_release(&rx_sem);rt_sem_detach(&rx_sem);}return RT_EOK;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(can_sample, can device sample);
MSH_CMD_EXPORT(can_sample_stop, can device sample stop);#endif

相关文章:

RT-Thread基于AT32单片机的CAN应用

1 硬件电路 2 RT-Thread驱动配置 RT-Studio中没有CAN相关的图形配置&#xff0c;需要手动修改board.h。在board.h的末尾&#xff0c;增加相关的BSP配置。 #define RT_CAN_USING_HDR #define BSP_USING_CAN13 IO配置 at32_msp.c中的IO配置是PB9和PB10&#xff0c;掌上实验室V…...

LeetCode---121双周赛---数位dp

题目列表 2996. 大于等于顺序前缀和的最小缺失整数 2997. 使数组异或和等于 K 的最少操作次数 2998. 使 X 和 Y 相等的最少操作次数 2999. 统计强大整数的数目 一、大于等于顺序前缀和的最小缺失整数 简单的模拟题&#xff0c;只要按照题目的要求去写代码即可&#xff0c;…...

RT-Thread I/O设备模型

I/O设备模型 绝大部分的嵌入式系统都包括一些I/O&#xff08;Input/Output&#xff0c;输入/输出&#xff09;设备&#xff0c;例如仪器上的数据显示屏、工业设备上的串口通信、数据采集设备上用于保存数据的Flash或SD卡&#xff0c;以及网络设备的以太网接口等&#xff0c;都…...

CloudCompare——拟合空间球

目录 1.拟合球2.软件操作3.算法源码4.相关代码 本文由CSDN点云侠原创&#xff0c;CloudCompare——拟合空间球&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫与GPT生成的文章。 1.拟合球 源码里用到了四点定球&#xff0c;…...

哪个牌子的护眼台灯适合学生?2024护眼台灯推荐

不知道各位父母对孩子的视力健康有没有关注&#xff0c;我国儿童青少年的近视率高达52.7%&#xff0c;也就是说&#xff0c;平均是个儿童中就有五个儿童存在视力问题&#xff0c;而且近视发生年龄提前至3到7岁。作为一名眼部护理博主&#xff0c;孩子从小看书、看屏幕起&#x…...

适用于动态 IT 环境的服务器流量监控软件

服务器在网络性能中起着至关重要的作用&#xff0c;这意味着保持其最佳容量至关重要。企业需要将 AI、ML 和云技术融入其 IT 中&#xff0c;从而提供充分的敏捷性、安全性和灵活性&#xff0c;在这方面&#xff0c;服务器流量监控已成为当务之急。通过定期监控通信、跟踪流量上…...

Java的Jar包和War包

在Java中&#xff0c;JAR&#xff08;Java Archive&#xff09;和WAR&#xff08;Web Archive&#xff09;都是用于打包和分发Java应用程序的压缩文件格式。它们在不同的应用场景中使用&#xff1a; JAR&#xff08;Java Archive&#xff09;&#xff1a; 用途&#xff1a; 主要…...

第二十一章 javascript数据代理(数据劫持)

文章目录 一、数据劫持对象的访问器属性 二、Object.defineProperty()三、Proxy()四、补充1. Object类新增方法2. Array类新增方法 一、数据劫持 数据劫持&#xff1a;能够拦截到数据被使用或被修改的时机&#xff0c;在这个时机除了可以获取数据的值或对数据的值进行修改之外…...

苹果电脑RAW图像处理软件Capture One Pro 22 mac软件介绍

Capture One Pro 22 for mac是一款专业的RAW文件转换器和图像编辑软件&#xff0c;拥有更新的处理引擎、市场领先的性能和强大的新功能&#xff0c;可为 500 多台高端相机提供具有美丽色彩和令人难以置信的细节的终极图像质量。 Capture One Pro 22 for Mac版软件介绍 Capture…...

phpcms v9后台添加草稿箱功能

一、后台添加文章模板phpcms/modules/content/templates/content_add.tpl.php中94行增加”保存草稿“按钮&#xff1a; <div class"button"><input value"<?php echo L(save_draft);?>" type"submit" name"dosubmit_draf…...

机器人持续学习基准LIBERO系列5——获取显示深度图

0.前置 机器人持续学习基准LIBERO系列1——基本介绍与安装测试机器人持续学习基准LIBERO系列2——路径与基准基本信息机器人持续学习基准LIBERO系列3——相机画面可视化及单步移动更新机器人持续学习基准LIBERO系列4——robosuite最基本demo 1.更改环境设置 LIBERO-master/l…...

Java 面试题 - 多线程并发篇

线程基础 创建线程有几种方式 继承Thread类 可以创建一个继承自Thread类的子类&#xff0c;并重写其run()方法来定义线程的行为。然后可以通过创建该子类的实例来启动线程。 示例代码&#xff1a; class MyThread extends Thread {public void run() {// 定义线程的行为} …...

2401d,讨论d串滑动参数

原文 因为对编译时执行的i串的兴趣,我一直在考虑搞个通用用例,而不是相关i串的用例. 滑动模板参数 请考虑以下模板: void pluto(string s)() {pragma(msg, s); } void test() {pluto!"hello"(); }因为s是编译时参数,这编译,而pragma(msg,s) 期望s为编译时值. voi…...

etcd官方docker镜像及dockerfile问题处理

解决下我之前etcd使用docker镜像启动的坑 1、问题镜像docker-file: 这个dockerfile看着看不出来问题,但如果有人真的执行我之前两篇文章的文件,就会有问题,什么问题呢,无法连接到etcd,由于我是刚装上docker,排查了一圈,包括docker网络及是否是本地docker的网络问题,…...

2023 IoTDB Summit:天谋科技高级开发工程师苏宇荣《汇其流:如何用 IoTDB 流处理框架玩转端边云融合》...

12 月 3 日&#xff0c;2023 IoTDB 用户大会在北京成功举行&#xff0c;收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题&#xff0c;多位学术泰斗、企业代表、开发者&#xff0c;深度分享了工业物联网时序数据库 IoTDB 的技术创新…...

Pygame程序的屏幕显示

不同对象的绘制与显示过程 在Pygame中&#xff0c;需要将所有需要在屏幕上显示的内容都绘制在一个display surface上。该Surface通常称为screen surface&#xff0c;它是pygame.display.set_mode()函数返回的Surface对象。 在绘制不同对象时&#xff0c;可以使用不同的绘制方…...

LVGL的List控件的触摸按键和实体按键的处理

在LVGL的List控件使用过程中&#xff0c;虽然通过触摸按键选择item&#xff0c;但是有些场景需要实体按键选取item&#xff0c;但是LVGL 的V8.3中没有像Emwin那样有函数选择list item的函数。LVGL中List引入了Group的概念&#xff0c;把列表项都添加到同一个group中。然后通过更…...

数据结构 模拟实现二叉树(孩子表示法)

目录 一、二叉树的简单概念 &#xff08;1&#xff09;关于树的一些概念 &#xff08;2&#xff09;二叉树的一些概念及性质 定义二叉树的代码&#xff1a; 二、二叉树的方法实现 &#xff08;1&#xff09;createTree &#xff08;2&#xff09;preOrder &#xff08;…...

Android14之解决刷机报错:Can not load Android system. Your data may be corrupt(一百七十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…...

二阶贝塞尔曲线生成弧线

概述 本文分享一个二阶贝塞尔曲线曲线生成弧线的算法。 效果 实现 1. 封装方法 class ArcLine {constructor(from, to, num 100) {this.from from;this.to to;this.num num;return this.getPointList();}getPointList() {const { from, to } thisconst ctrlPoint thi…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...