23:【stm32】ADC模数转换器

2024-09-03 00:20
文章标签 stm32 23 adc 模数转换器

本文主要是介绍23:【stm32】ADC模数转换器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ADC模数转换器

  • 1、ADC的简介
  • 2、逐次逼近型ADC
  • 3、采样时间和转换时间
  • 4、STM32中ADC模块
  • 5、编程案列
    • 5.1、AD单通道
    • 5.2、AD多通道

1、ADC的简介

ADC就是一个模数转换器,将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。说的直观一点就是一个电压表,用于测量电压的片上外设。其中转换电压的范围0~3.3v

在这里插入图片描述
其中这些传感器在有外界的刺激的情况下,将会改变自身电阻的大小(如下图N1电阻),进而改变输出电压的大小。而电压的大小通过模拟输出口AO口输出。单片机可以通过ADC获取外部模块的电压值,进而做出一些动作。
在这里插入图片描述
那么单片机是怎样通过ADC进行对外部电压的测量并转换为数字量保存在内存中喃?

答案:比较器将ADC的结果寄存器里面的数据(DAC转换)和模拟信号进行比较,
①若ADC的结果寄存器里面的数据<模拟信号,则增加ADC的结果寄存器里面的数据。
②若ADC的结果寄存器里面的数据>模拟信号,则减小ADC的结果寄存器里面的数据。
③若ADC的结果寄存器里面的数据=模拟信号,则将数据保存到DMA中。

STM32F103C8T6有2个ADC,假如ADC的结果寄存器是2位,那么分辨率是多少喃?如下图
在这里插入图片描述
若结果寄存器是4位喃?是8位喃?

在这里插入图片描述

2、逐次逼近型ADC

我们先来了解一下ADC的工作原理,如下图所示:
在这里插入图片描述

如图:当闭合采样开关,模拟信号输入,对电容充电。当充满电后,断开采样开关,比较器通过比较来给结果寄存器增加数据/减少数据,直到和模拟信号的值相差到规定的数值以内,然后将数据保存并转换。如下图为模拟信号为2.21v。

在这里插入图片描述
则结果寄存器的数据最后为1010。

3、采样时间和转换时间

采样时间就是对电容充满电所需要的时间,而转换时间就是通过比较,确定结果寄存器里面的数值的时间。
而ADC挂载在APB2总线上,但是ADC的特性规定,ADC的时钟<14MHz。所以APB2时钟出来后还要被分频才能够给ADC通过时钟源。

在这里插入图片描述
在这里插入图片描述

  • 转换时间 = 12.5的时钟周期。

在这里插入图片描述

  • 采样时间 = 电容充电的时间
    电容充电的时间越长,采样的数据就越精确,误差就越小。
    在这里插入图片描述但是ADC的精度本来就是有限的,只要我们采样的误差<1/4*ADC分辨率即可。
    在这里插入图片描述电容充电的时间由电路中的电阻决定的,电阻越大,电流越小,充电时间越长,采样时间越长。
    在这里插入图片描述
    假设ADC的时钟源频率为14MH在,则
    在这里插入图片描述但是在编程中采样时间是规定了8个挡位的,所以我们只能选择和采样时间相近的那个挡位。挡位>采样时间,数据越精确。挡位<采样时间,数据变化的越快

问:最理想的情况下ADC每砂最多执行多少次转换

在这里插入图片描述
所以:理想情况下1us转换1次数据,则1s转换1000000次。

4、STM32中ADC模块

STM32F103C8T6单片机中有2个ADC模块:ADC1、ADC2,结果寄存器都为12位。也就是将3.3v的电压分为了4095份。且每个ADC片上外设都有10外部测量通道和2个内部信号源。我们可以通过外部通道测量外部模块的电压
在这里插入图片描述
这么多的通道是怎样管理的喃?
答案是:通过规则组(常规序列)和注入组(注入序列)进行管理

在这里插入图片描述

+如上图所示:规则组和注入组就像是一个盒子(用来存放需要测量的物件),ADC就像是一个工人。
① 规则组:规则组里面最多能对16个通道采集转换(盒子里面最多能放16个物件等待被测量),而存放采集转换的数据的盒子只有一个。所以只有等第一个的数据被DMA挪走后,第二个数据才能放入盒子里面
② 注入组:注入组里面最多能对4个通道采集转换,而又有4个盒子专门存放数据。
③触发控制:让ADC开始采集转换的信号(让工人开始测量),如下图所示,有定时器启动和软件启动。而软件启动就是就是给寄存器置1
在这里插入图片描述

在这里插入图片描述

规则组的转换模式:
①单次转换非扫描模式
在这里插入图片描述
在此模式下,规则组只有第一个盒子里面的通道才有效(即序列1),我们可以在序列1的盒子里面放入我们需要转换的通道,然后给规则组一个触发信号,开始采集转换,转换完成后数据保存在数据寄存器里面,同时给ECO置1。需要进行第二次转换,那么需要在启动一次触发信号,开启转换。

②连续转换非扫描模式
在这里插入图片描述
和单次转换非扫描模式不同的是,给规则组一个触发信号,在第一次转换完成后立马进入第二次转换,不断的进行下去。单片机需要获取数据,只需要读取数据寄存器里面的数据即可

③单次转换扫描模式

在这里插入图片描述
在规则组里面的多个盒子里面放入我们需要转换的通道,然后告诉ADC有多少个盒子,转换完成后依次存放在数据寄存器里面。ECO置1,需要第二次转换则需要启动触发信号。

④连续转换扫描模式
在这里插入图片描述

数据对齐:
ADC转换后的数据是12位的,而数据寄存器是16位的,所以数据寄存器有4个空出来的位置补零。一般的情况下使用右对齐即可
在这里插入图片描述

数据校准
校准都是固定的,只需要在初始化后加上校准代码即可,不用理解。
在这里插入图片描述

5、编程案列

与之相关的标准库编程接口:
在这里插入图片描述

5.1、AD单通道

ADC.c文件的代码如下;

/*ADC单通道实验,通过通道1(PA0)对自身输出电压进行采集,通过电位器改变电压变化,最终在OLED上面显示出来
*/
#include "stm32f10x.h"                  // Device headervoid AD_Init(void)
{//1.开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//2.对ADC时钟进行分频RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHZ/6 = 12MHz//3.对通道1(PA0)进行配置GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入模式,ADC的专属模式GPIOInitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA,&GPIOInitStruct);//4.对ADC规则组进行配置ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//ADC几,通道,序列,采样时间//5.初始化ADCADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//工作模式:独立模式/双ADC模式,这里的独立模式ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//ADC触发选择,选择软件触发ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//连续/单次模式,这里选择单次ADC_InitStruct.ADC_ScanConvMode = DISABLE;//扫描/非扫描,这里选择非扫描ADC_InitStruct.ADC_NbrOfChannel = 1;//在扫描模式下的盒子数目ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐,右对齐ADC_Init(ADC1,&ADC_InitStruct);//6.开启ADC电源ADC_Cmd(ADC1,ENABLE);//7.校准ADC_ResetCalibration(ADC1);//将校准复位,给CR2_RSTCAL置1,进行复位while(ADC_GetResetCalibrationStatus(ADC1) == SET);//复位完成,硬件置0ADC_StartCalibration(ADC1);//开始校准,给CR2_CAL置1while(ADC_GetCalibrationStatus(ADC1) == SET);//校准完成,硬件置0}uint16_t AD_GetValue(void)//获取数据寄存器里面的数据
{ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待ECO置1,代表转换完成return ADC_GetConversionValue(ADC1);//获取ADCx->DR里面的数据,ECO自动清除
}

【注】如果使用连续非扫描模式那么ADC.c文件的代码如下:

#include "stm32f10x.h"                  // Device headervoid AD_Init(void)
{//1.开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//2.对ADC时钟进行分频RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHZ/6 = 12MHz//3.对通道1(PA0)进行配置GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入模式,ADC的专属模式GPIOInitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA,&GPIOInitStruct);//4.对ADC规则组进行配置ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//ADC几,通道,序列,采样时间//5.初始化ADCADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//工作模式:独立模式/双ADC模式,这里的独立模式ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//ADC触发选择,选择软件触发ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;//连续/单次模式,这里选择单次ADC_InitStruct.ADC_ScanConvMode = DISABLE;//扫描/非扫描,这里选择非扫描ADC_InitStruct.ADC_NbrOfChannel = 1;//在扫描模式下的盒子数目ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐,右对齐ADC_Init(ADC1,&ADC_InitStruct);//6.开启ADC电源ADC_Cmd(ADC1,ENABLE);//7.校准ADC_ResetCalibration(ADC1);//将校准复位,给CR2_RSTCAL置1,进行复位while(ADC_GetResetCalibrationStatus(ADC1) == SET);//复位完成,硬件置0ADC_StartCalibration(ADC1);//开始校准,给CR2_CAL置1while(ADC_GetCalibrationStatus(ADC1) == SET);//校准完成,硬件置0ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待ECO置1,代表转换完成}uint16_t AD_GetValue(void)//获取数据寄存器里面的数据
{
//	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
//	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待ECO置1,代表转换完成return ADC_GetConversionValue(ADC1);//获取ADCx->DR里面的数据,ECO自动清除
}

主程序文件的代码如下:

/*ADC单通道的简单使用
*/#include "stm32f10x.h"                 
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"uint16_t Value;
float Voltage;				//定义电压变量int main(void)
{AD_Init();OLED_Init();OLED_Clear();OLED_ShowString(1,1,"Value:");OLED_ShowString(2,1,"Voltage:0.00V");while(1){Value = AD_GetValue();//获取数据Voltage = (Value * 3.3) / 4095;//转换为电压值OLED_ShowNum(1,7,Value,4);//显示数据OLED_ShowNum(2,9,Voltage,1);//显示电压值的整数部分OLED_ShowNum(2,11,(uint16_t)(Voltage*100) % 100,2);//显示电压值的小数部分Delay_ms(100);}
}

5.2、AD多通道

我们还没有学习DMA,使用如果不使用DMA对多通道转换的数据进行挪动的话,那么会出现数据的覆盖。我们通过单次转换非扫描模式模拟单次扫描模式。就是在第一次转换完成后,将第一序列的盒子里面的通道通过手动修改。
ADC.c文件的代码如下:

#include "stm32f10x.h"                  // Device headervoid AD_Init(void)
{//1.开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//2.对ADC时钟进行分频RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHZ/6 = 12MHz//3.对通道1(PA0)进行配置GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入模式,ADC的专属模式GPIOInitStruct.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_Init(GPIOA,&GPIOInitStruct);//4.对ADC规则组进行配置
//	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//ADC几,通道,序列,采样时间//5.初始化ADCADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//工作模式:独立模式/双ADC模式,这里的独立模式ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//ADC触发选择,选择软件触发ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//连续/单次模式,这里选择单次ADC_InitStruct.ADC_ScanConvMode = DISABLE;//扫描/非扫描,这里选择非扫描ADC_InitStruct.ADC_NbrOfChannel = 1;//在扫描模式下的盒子数目ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐,右对齐ADC_Init(ADC1,&ADC_InitStruct);//6.开启ADC电源ADC_Cmd(ADC1,ENABLE);//7.校准ADC_ResetCalibration(ADC1);//将校准复位,给CR2_RSTCAL置1,进行复位while(ADC_GetResetCalibrationStatus(ADC1) == SET);//复位完成,硬件置0ADC_StartCalibration(ADC1);//开始校准,给CR2_CAL置1while(ADC_GetCalibrationStatus(ADC1) == SET);//校准完成,硬件置0
}uint16_t AD_GetValue(uint8_t ADC_Channel)//获取数据寄存器里面的数据,指定通道
{ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);//ADC几,通道,序列,采样时间ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待ECO置1,代表转换完成return ADC_GetConversionValue(ADC1);//获取ADCx->DR里面的数据,ECO自动清除
}

主程序文件的代码如下:

/*ADC单通道的简单使用
*/#include "stm32f10x.h"                 
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"uint16_t Value1,Value2,Value3,Value4;int main(void)
{AD_Init();OLED_Init();OLED_Clear();OLED_ShowString(1,1,"Value1:");OLED_ShowString(2,1,"Value2:");OLED_ShowString(3,1,"Value3:");OLED_ShowString(4,1,"Value4:");while(1){Value1 = AD_GetValue(ADC_Channel_0);//获取通道1数据,手动修改第一序列的通道Value2 = AD_GetValue(ADC_Channel_1);//获取通道2数据Value3 = AD_GetValue(ADC_Channel_2);//获取通道3数据Value4 = AD_GetValue(ADC_Channel_3);//获取通道4数据OLED_ShowNum(1,8,Value1,4);OLED_ShowNum(2,8,Value2,4);OLED_ShowNum(3,8,Value3,4);OLED_ShowNum(4,8,Value4,4);Delay_ms(100);}
}

【注】此方法不能在连续非扫描情况下模拟连续扫描模式。
因为:连续非扫描模式下,只需要一次的触发信号,如果模拟连续扫描模式,则需要手动修改通道,而修改通道后没有触发信号来进行触发。

#include "stm32f10x.h"                  // Device headervoid AD_Init(void)
{//1.开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//2.对ADC时钟进行分频RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHZ/6 = 12MHz//3.对通道1(PA0)进行配置GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入模式,ADC的专属模式GPIOInitStruct.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_Init(GPIOA,&GPIOInitStruct);//4.对ADC规则组进行配置
//	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//ADC几,通道,序列,采样时间//5.初始化ADCADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//工作模式:独立模式/双ADC模式,这里的独立模式ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//ADC触发选择,选择软件触发ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;//连续/单次模式,这里选择单次ADC_InitStruct.ADC_ScanConvMode = DISABLE;//扫描/非扫描,这里选择非扫描ADC_InitStruct.ADC_NbrOfChannel = 1;//在扫描模式下的盒子数目ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐,右对齐ADC_Init(ADC1,&ADC_InitStruct);//6.开启ADC电源ADC_Cmd(ADC1,ENABLE);//7.校准ADC_ResetCalibration(ADC1);//将校准复位,给CR2_RSTCAL置1,进行复位while(ADC_GetResetCalibrationStatus(ADC1) == SET);//复位完成,硬件置0ADC_StartCalibration(ADC1);//开始校准,给CR2_CAL置1while(ADC_GetCalibrationStatus(ADC1) == SET);//校准完成,硬件置0ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待ECO置1,代表转换完成
}uint16_t AD_GetValue(uint8_t ADC_Channel)//获取数据寄存器里面的数据
{ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);//ADC几,通道,序列,采样时间
//	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
//	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待ECO置1,代表转换完成return ADC_GetConversionValue(ADC1);//获取ADCx->DR里面的数据,ECO自动清除
}

上面的代码为连续非扫描情况下模拟连续扫描模式的ADC.c文件的代码,需要手动修改通道的在软件触发之后,这是不允许的,因为等规则组里面的配置完整后,在给触发信号这样正确。

这篇关于23:【stm32】ADC模数转换器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131490

相关文章

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

基于stm32的河流检测系统-单片机毕业设计

文章目录 前言资料获取设计介绍功能介绍具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机设计精品

STM32的使用方法一

注:我采用的是STM32F103RC芯片、相应的电路图和STM32CubeIDE软件这是在STM32CubeIDE软件定义芯片后,所给的必要的代码逻辑,加上了注释 #include "main.h"/* Private variables ---------------------------------------------------------*//* Private function

STM32 HAL CAN通讯 实操

1、简介 相比于串口通讯,对于刚接触CAN通讯的小白来说,CAN通讯相对复杂,看各种视频、帖子理论,总是一知半解。本次通过傻瓜式操作,先实现CAN通讯的交互,以提高小白的信心,也便于自己复习观看。本次以STM32CubeMX进行初始化配置,通过Keil 5软件进行软件设计,通过CAN盒实现进行数据的交互。该流程实际以STM32F0、F1、F3、F4、F7实测好用(理论上都适用),这三种型号单片机