stm32入门学习11-硬件I2C和MPU
(一)I2C硬件电路
stm32内部有I2C的硬件电路,我们可以使用stm32的标准库函数来实现I2C,这可以为我们减少对软件资源的占用
I2C硬件电路常用的标准库函数
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);
//通过结构体初始化I2Cvoid I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);
//给初始化结构体赋默认值void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
//使能I2C,初始化之后要使能其才开始工作void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
//开始I2C传输void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);
//结束I2C传输void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
//发送一个字节数据uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);
//接收一个字节数据void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
//发送7位地址,在最开始I2C寻址调用这个函数ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);
//接收事件,在使用硬件开始传输或发送数据等操作之后都会有对应的事件需要接收判断后再执行下一个操作void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);
//设置响应为,相当于软件实现I2C中的ack
我们只要使用这些库函数,按照其规定的流程进行数据的发送和接收即可,不需要我们手动在软件中模拟I2C的高低电平跳变
(二)使用库函数实现I2C数据的发送与接收
(1)发送
I2C发送流程如图,在开始传输完成后,其会产生EV5事件,我们在事件产生后即可发送地址位,成功发送后会产生EV6事件,接着发送寄存器地址,因为这里使用的是一个寄存器和一个移位寄存器来发送数据,所以我们在寄存器的数据写入到移位寄存器中正在发送(EV8事件)即可将新的数据写入寄存器,在最后一个数据位我们没有数据写入寄存器,且移位寄存器发送完毕,会产生EV8_2事件,表示发送完成,然后即可停止传输

这里我们发送一个字节后的接收响应由硬件自动接收,不需要我们手动接收响应
由于我们会频繁接收各种事件,我们可以把接收事件的函数封装成一个简单的函数,且让其超时退出,不让程序卡死

接收事件函数
void mpu_wait_flag(int event)
{unsigned int time = 10000;while (I2C_CheckEvent(I2C2, event) != SUCCESS){time--;if (time == 0){break;}}
}
按照流程,我们可以这样编写发送函数
发送函数
void mpu_write(unsigned char address, unsigned char inf)
{I2C_GenerateSTART(I2C2, ENABLE);mpu_wait_flag(I2C_EVENT_MASTER_MODE_SELECT); //EV5I2C_Send7bitAddress(I2C2, mpu_address, I2C_Direction_Transmitter);mpu_wait_flag(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV6I2C_SendData(I2C2, address);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTING); //EV8I2C_SendData(I2C2, inf);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2I2C_GenerateSTOP(I2C2, ENABLE);
}
第一行我们先开始传输,第二行我们接收EV5事件,第三行我们发送7位地址,并且第三个参数为读模式还是写模式,我们选择写模式,第四行我们等待EV6事件,紧接着第五行发送要读取的寄存器地址,第六行等待寄存器地址移动到移位寄存器正在发送事件(EV8),最后第七行写要发送的数据,等待发送完成事件,最后停止传输;
(2)接收
接收数据的流程如图所示
这里一样,我们在开始之后会产生EV5事件,在传递MPU地址后会产生EV6事件,接着读取数据,这里由于我们在读取事件之后硬件电路会立刻把我们之前预设的ack响应发给从机,因此我们需要在读取最后一个数据之前把ack置0,我们这里只读取一个字节的数据,也就是要在发送MPU地址之后,读取数据之前先把ack置0,对应代码如下
unsigned char mpu_read(unsigned char address)
{unsigned char inf;I2C_GenerateSTART(I2C2, ENABLE);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTED);I2C_Send7bitAddress(I2C2, mpu_address, I2C_Direction_Transmitter);mpu_wait_flag(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);I2C_SendData(I2C2, address);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTED);I2C_GenerateSTART(I2C2, ENABLE);mpu_wait_flag(I2C_EVENT_MASTER_MODE_SELECT);I2C_Send7bitAddress(I2C2, mpu_address, I2C_Direction_Receiver);mpu_wait_flag(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);I2C_AcknowledgeConfig(I2C2, DISABLE); //ack=0mpu_wait_flag(I2C_EVENT_MASTER_BYTE_RECEIVED);inf = I2C_ReceiveData(I2C2);I2C_GenerateSTOP(I2C2, ENABLE);I2C_AcknowledgeConfig(I2C2, ENABLE);return inf;
}
第一段对应我们软件I2C的给寄存器地址操作,我们仍需要先写入寄存器地址,然后在第二段我们重新开始传输,接收EV5事件后发送MPU地址,这里第三个参数选择读模式,等待地址发送完成,之后值得注意的是我们先执行的不是读取数据,而是先把应答位置非应答,再去读取数据,读取完成后我们即可停止传输
(三)MPU-6050
经过上面两个函数的编写,我们已经可以调用上面两个函数来实现在指定外设寄存器上写数据和读数据的操作,我们即可进行MPU的初始化和读取转换数据所在的寄存器,这里就和之前使用软件模拟I2C的代码没有什么区别,因为软件我们只是模拟了I2C的波形,最终也封装成了写字节和读字节的函数
(1)初始化
(1)打开时钟和初始化GPIO
这里因为我们使用内部的I2C硬件电路,因此我们打开时钟我们要把I2C的时钟打开,stm32F03C8有两个I2C,这里使用的是I2C2,对应的SCL、SDA引脚为PB10、PB11

void mpu_rcc_init()
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
}
初始化GPIO,这里要用复用开漏输出
void mpu_gpio_init()
{GPIO_InitTypeDef gpio_init;gpio_init.GPIO_Pin = SCL | SDA;gpio_init.GPIO_Mode = GPIO_Mode_AF_OD;gpio_init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &gpio_init);
}
(2)I2C初始化
使用I2C硬件电路还要对I2C进行初始化,可以看下初始化结构体

(1)第一个参数是选择时钟速度,数值越大电平翻转频率越高,低于100KHz的是正常模式,高于100KHz的是高速模式,这里选择100KHz;
(2)第二个参数是选择模式,可以选泽I2C模式、SMBus设备模式或SMBus主控模式,这里选择I2C模式;
(3)第三个参数是选择高低电平的占空比,这里只有在高速模式下有效,有16:9和2:1两种可选,这里不是高速模式,可以随便选择;
(4)第四个参数是选择自身地址,自身可以作为从机,设置自身地址让其他主机呼叫,随便选择,只要不和MPU或其他I2C上的地址冲突即可;
(5)第五个参数是应答位设置,可以选择应答和非应答,给应答;
(6)第六个参数是选择7位地址模式还是10位地址模式,这里选择7为地址模式;
这样我们就可以初始化I2C了
void mpu_i2c_init()
{I2C_InitTypeDef i2c_init;i2c_init.I2C_ClockSpeed = 100000;i2c_init.I2C_Mode = I2C_Mode_I2C;i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;i2c_init.I2C_OwnAddress1 = 0x00;i2c_init.I2C_Ack = I2C_Ack_Enable;i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Init(I2C2, &i2c_init);I2C_Cmd(I2C2, ENABLE);
}
最后不要忘了使能I2C,否则其不工作
(3)MPU初始化
我们把时钟、gpio、I2C的初始化都集成于此,我们还要像软件那样配置寄存器来关闭MPU睡眠模式和选择时钟等功能,具体代码如下
void mpu_init()
{mpu_rcc_init();mpu_gpio_init();mpu_i2c_init();mpu_write(0x6B, 0x01); //PWR_MGMT_1 -> 0000 0001mpu_write(0x6C, 0x00); //PWR_MGMT_2 -> 0000 0000}mpu_write(0x19, 0x09); //SMPLRT_DIV -> 0000 1001mpu_write(0x1A, 0x06); //CONFIG -> 0000 0110mpu_write(0x1B, 0x18); //GYRO_CONFIG -> 0001 1000mpu_write(0x1C, 0x18); //ACCEL_CONFIG -> 0001 1000
}
(2)读取参数
最后我们选择将x轴、y轴和z轴的加速度和角速度放在一个结构体中返回,我们还要注意16位整数转为32位整数中的符号问题
结构体定义
typedef struct infs
{int x_acceleration;int y_acceleration;int z_acceleration;int x_angular_velocity;int y_angular_velocity;int z_angular_velocity;
} information;
16位整数转32为整数
int mpu_16_to_32(int original)
{int final;if (original & 0x8000){final = original | 0xFFFF0000;}return final;
}
我们只要读取MPU对应数据的寄存器即可,这里和软件模拟的操作一样
information mpu_get_inf()
{uint8_t inf_L;uint8_t inf_H;information infor;inf_H = mpu_read(0x3B);inf_L = mpu_read(0x3C);infor.x_acceleration = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x3D);inf_L = mpu_read(0x3E);infor.y_acceleration = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x3F);inf_L = mpu_read(0x40);infor.z_acceleration = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x43);inf_L = mpu_read(0x44);infor.x_angular_velocity = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x45); inf_L = mpu_read(0x46); infor.y_angular_velocity = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x47); inf_L = mpu_read(0x48); infor.z_angular_velocity = mpu_16_to_32((inf_H<<8) | inf_L);return infor;
}
(3)封装与声明
最后的.c 和 .h文件如下
#include "stm32f10x.h" // Device header#define SCL GPIO_Pin_10
#define SDA GPIO_Pin_11#define mpu_address 0xD0void mpu_wait_flag(int event)
{unsigned int time = 10000;while (I2C_CheckEvent(I2C2, event) != SUCCESS){time--;if (time == 0){break;}}
}void mpu_write(unsigned char address, unsigned char inf)
{I2C_GenerateSTART(I2C2, ENABLE);mpu_wait_flag(I2C_EVENT_MASTER_MODE_SELECT); //EV5I2C_Send7bitAddress(I2C2, mpu_address, I2C_Direction_Transmitter);mpu_wait_flag(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV6I2C_SendData(I2C2, address);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTING); //EV8I2C_SendData(I2C2, inf);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTED); //EV8_2I2C_GenerateSTOP(I2C2, ENABLE);
}unsigned char mpu_read(unsigned char address)
{unsigned char inf;I2C_GenerateSTART(I2C2, ENABLE);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTED);I2C_Send7bitAddress(I2C2, mpu_address, I2C_Direction_Transmitter);mpu_wait_flag(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);I2C_SendData(I2C2, address);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_TRANSMITTED);I2C_GenerateSTART(I2C2, ENABLE);mpu_wait_flag(I2C_EVENT_MASTER_MODE_SELECT);I2C_Send7bitAddress(I2C2, mpu_address, I2C_Direction_Receiver);mpu_wait_flag(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);I2C_AcknowledgeConfig(I2C2, DISABLE);mpu_wait_flag(I2C_EVENT_MASTER_BYTE_RECEIVED);inf = I2C_ReceiveData(I2C2);I2C_GenerateSTOP(I2C2, ENABLE);I2C_AcknowledgeConfig(I2C2, ENABLE);return inf;
}void mpu_rcc_init()
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
}void mpu_gpio_init()
{GPIO_InitTypeDef gpio_init;gpio_init.GPIO_Pin = SCL | SDA;gpio_init.GPIO_Mode = GPIO_Mode_AF_OD;gpio_init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &gpio_init);
}void mpu_i2c_init()
{I2C_InitTypeDef i2c_init;i2c_init.I2C_ClockSpeed = 100000;i2c_init.I2C_Mode = I2C_Mode_I2C;i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;i2c_init.I2C_OwnAddress1 = 0x00;i2c_init.I2C_Ack = I2C_Ack_Enable;i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Init(I2C2, &i2c_init);I2C_Cmd(I2C2, ENABLE);
}void mpu_init()
{mpu_rcc_init();mpu_gpio_init();mpu_i2c_init();mpu_write(0x6B, 0x01); //PWR_MGMT_1 -> 0000 0001mpu_write(0x6C, 0x00); //PWR_MGMT_2 -> 0000 0000}mpu_write(0x19, 0x09); //SMPLRT_DIV -> 0000 1001mpu_write(0x1A, 0x06); //CONFIG -> 0000 0110mpu_write(0x1B, 0x18); //GYRO_CONFIG -> 0001 1000mpu_write(0x1C, 0x18); //ACCEL_CONFIG -> 0001 1000
}typedef struct infs
{int x_acceleration;int y_acceleration;int z_acceleration;int x_angular_velocity;int y_angular_velocity;int z_angular_velocity;
} information;int mpu_16_to_32(int original)
{int final;if (original & 0x8000){final = original | 0xFFFF0000;}return final;
}information mpu_get_inf()
{uint8_t inf_L;uint8_t inf_H;information infor;inf_H = mpu_read(0x3B);inf_L = mpu_read(0x3C);infor.x_acceleration = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x3D);inf_L = mpu_read(0x3E);infor.y_acceleration = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x3F);inf_L = mpu_read(0x40);infor.z_acceleration = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x43);inf_L = mpu_read(0x44);infor.x_angular_velocity = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x45); inf_L = mpu_read(0x46); infor.y_angular_velocity = mpu_16_to_32((inf_H<<8) | inf_L);inf_H = mpu_read(0x47); inf_L = mpu_read(0x48); infor.z_angular_velocity = mpu_16_to_32((inf_H<<8) | inf_L);return infor;
}
#ifndef __MPU_H__
#define __MPU_H__typedef struct infs
{int x_acceleration;int y_acceleration;int z_acceleration;int x_angular_velocity;int y_angular_velocity;int z_angular_velocity;
} information;void mpu_init(void);
information mpu_get_inf(void);#endif
(四)主函数调用
我们只要在主函数开始时对MPU初始化,然后在循环中调用读取寄存器值的函数即可,和软件模拟实现的程序一样
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "MPU.h"
#include "Delay.h"
int main()
{mpu_init();OLED_Init();information inf;while(1){inf = mpu_get_inf();OLED_ShowSignedNum(1, 1, inf.x_acceleration, 5);OLED_ShowSignedNum(2, 1, inf.y_acceleration, 5);OLED_ShowSignedNum(3, 1, inf.z_acceleration, 5);OLED_ShowSignedNum(1, 8, inf.x_acceleration, 5);OLED_ShowSignedNum(2, 8, inf.y_acceleration, 5);OLED_ShowSignedNum(3, 8, inf.z_acceleration, 5);Delay_ms(500);}return 0;
}
(五)总结
在学习软件模拟I2C后,这里学习的是通过硬件I2C,通过库函数来实现I2C通信,读取MPU寄存器中的数据,我们对I2C的理解更加深入,对stm32的了解也更加具体
相关文章:
stm32入门学习11-硬件I2C和MPU
(一)I2C硬件电路 stm32内部有I2C的硬件电路,我们可以使用stm32的标准库函数来实现I2C,这可以为我们减少对软件资源的占用 I2C硬件电路常用的标准库函数 void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct); /…...
如何在C++、PHP、GO中使用AI生成PPT API接口
在当今快节奏的商业环境中,演示文稿的制作不仅需要快速,还需要具有吸引力和专业性。AI生成PPT API 服务提供了一种创新的解决方案,能够根据用户提供的内容自动生成演示文稿,极大地提高了效率和质量。本文将详细介绍AI生成PPT的优势…...
力扣面试150 逆波兰表达式求值 栈 模拟栈
Problem: 150. 逆波兰表达式求值 👨🏫 参考题解 class Solution {//纯数组模拟栈实现(推荐) 3 ms 36 MBpublic static int evalRPN(String[] tokens) {int[] numStack new int[tokens.length / 2 1];int index 0;for (String s : tokens) {swit…...
动手学深度学习V2每日笔记(深度卷积神经网络AlexNet)
本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1h54y1L7oe/spm_id_from333.788.recommend_more_video.0&vd_sourcec7bfc6ce0ea0cbe43aa288ba2713e56d 文档教程 https://zh-v2.d2l.ai/ 本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录&…...
室内定位:紧耦合的学习惯性里程 (TLIO)
a### TLIO论文解读:紧耦合的学习惯性测程 (TLIO) 在惯性测量单元 (IMU) 领域,如何在短时间内精确地估计位置和姿态一直是一个挑战。最近,论文《TLIO: Tight Learned Inertial Odometry》提出了一种创新的方法,通过将深度学习与扩展卡尔曼滤波器 (EKF) 紧密结合,来解决这一…...
【面试之算法篇】寻找二叉树中两个节点的最低公共祖先
题目 给定一个树的根节点root和两个子节点a,b,返回二叉树中两个节点的最低公共祖先。二叉树每个节点的值都是不同的整数 10060 12040 null 4 74和7的最低公共祖先是120,60和40的最低公共祖先是60 思路 两个节点的祖先会有多个,只有是祖先的节点才有可能会是最低公共…...
使用Unity开发编辑系统时复制物体的一些细节问题
首先是复制一个GameObject时组件中的变量内容的复制问题,这个在Unity复制对象时让私有变量也被复制的简单方法这篇博客里面做了说明,但是其实还有一个问题,就是有些时候需要被复制的物体在刚创建出来的时候需要自动执行一些操作,这…...
【C++】模版初阶+STL简介
🚀个人主页:奋斗的小羊 🚀所属专栏:C 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 前言💥1、函数模版💥1.1 函数模板概念💥1.2 函数模板格式💥1…...
Vue3中的toRef和toRefs的区别和用法
刚做了Ref和Reactive区别及使用方法笔记,再来总结一下,toRef 和 toRefs 的作用、用法、区别 1、作用和区别 toRef 和 toRefs 可以用来复制 reactive 里面的属性然后转成 ref,而且它既保留了响应式,也保留了引用,也就…...
【docker快捷部署系列一】docker快速入门,安装docker,解决运行Docker Quickstart Terminal出错
1、docker快速入门 视频链接 知识点概述 docker是轻量级虚拟机image是镜像 相当于虚拟机快照container是容器,相当于运行起来的虚拟机程序Dockerfile 是创建docker镜像的自动化脚本docker-compose 是一个定义和运行多个容器命令的工具,包括运行Docker…...
vulnhub靶机实战_DC-8
一、靶机下载 靶机下载链接汇总:https://download.vulnhub.com/使用搜索功能,搜索dc类型的靶机即可。本次实战使用的靶机是:DC-8系统:Debian下载链接:https://download.vulnhub.com/dc/DC-8.zip 二、靶机启动 下载完…...
如何做到项目真实性优化?保姆级写简历指南第五弹!
大家好,我是程序员鱼皮。做知识分享这些年来,我看过太多简历、也帮忙修改过很多的简历,发现很多同学是完全不会写简历的、会犯很多常见的问题,不能把自己的优势充分展示出来,导致措施了很多面试机会,实在是…...
Python Beautiful Soup介绍
在Web数据抓取和网页解析的世界里,Python以其简洁的语法和丰富的库资源成为了许多开发者的首选语言。而Beautiful Soup,作为Python中一个强大的HTML和XML解析库,更是以其易用性和灵活性赢得了广泛的赞誉。本文将带你走进Beautiful Soup的世界…...
NDI Tools汉化版的安装
目录 一、安装包下载 二、安装英文版 三、安装汉化版 NDI(Network Device Interface)即网络设备接口,是由美国 NewTek 公司开发的免费标准,它可使兼容的视频产品以高质量、低延迟、精确到帧的方式通过网络进行通讯、传输和接收广播级质量的视频,非常适合在现场直播制作…...
【JAVA多线程】AQS,JAVA并发包的核心
目录 1.概述 1.1.什么是AQS 1.2.AQS和BlockQueue的区别 1.3.AQS的结构 2.源码分析 2.1.CLH队列 2.2.模板方法的实现 2.2.1.独占模式 1.获取资源 2.释放资源 2.2.2.共享模式 1.概述 1.1.什么是AQS AQS非常非常重要,可以说是JAVA并发包(java.…...
springcloud loadbalancer nacos无损发布
前言 故事背景 jenkins部署时总是会有几秒钟接口调用报错,观察日志是因为流量被下发到已下线的服务,重启脚本在停止应用之前先调用nacos注销实例api后再重启依然会短暂出现此问题。项目架构是springcloud alibaba,通过openfeign进行微服务之间调用&…...
React原理
函数式编程 一种编程范式,概念比较多纯函数不可变值vdom和diff Vue2.x Vue3.x React 三者实现vdom细节都不同核心概念和实现思路,都一样h函数 用来生成vnode的函数 vnode数据结构 {tag: div,props: {className: div-class},children: [{tag: p,children: 测试}, ...] }pat…...
React-Native优质开源项目
React Native是由Facebook开发的一种开源框架,它允许开发者使用JavaScript和React编写原生应用,提供了一套跨平台的UI组件,可以在iOS和Android上实现一致的用户体验。在React Native的生态系统中,有许多优质的开源项目,…...
Ajax-02
一.form-serialize插件 作用:快速收集表单元素的值 const form document.querySelector(.example-form) const data serialize(form,{hash:true,empty:true}) *参数1:要获取哪个表单的数据 表单元素设置name属性,值会作为对象的属性名 建议…...
供应商较多的汽车制造业如何选择供应商协同平台?
汽车制造业的供应商种类繁多,根据供应链的不同环节和产品特性,可以大致分为以下几类。 按供应链等级分包括: 一级供应商通常具有较高的技术水平和生产能力,能够满足汽车厂商对零部件的高品质、高性能和高可靠性的要求。 二级供应…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
