STM32之ADC的学习心得(std+HAL)

STM32的ADC配置问题

问题介绍

最近要使用STM32F103C8T6来做个数字万用表,于是开始学习STM32,要用到32内部的12位ADC
等于是刚刚接触STM32,一切从零开始,现在分享下如何简单的使用ADC


预备知识

RCC:
这个是用来设置时钟的,比如我可以设置我的系统时钟频率等
TIM:
顾名思义,是timer的缩写,是定时计数器.
RCC 和 TIM的区别:
RCC用来设置我32的系统时钟频率或者是一些其他硬件的时钟频率
而TIM是在某个时钟频率下工作的一个计数器,这个频率可以来自RCC的设置,也可以来自外部
注意,RCC设置频率的来源也可以是外部或者内部(内部不准确,我们一般不用,这也是为什么要外接8MHz晶振的原因),而后产生一个内部时钟频率送给TIM

为什么要说时钟呢?因为我要使ADC的采样率达到最大,也就是1MHz的采样率,而达到这样的采样率就需要设置ADC的时钟频率,ADC最大时钟频率是14MHz。这两者什么关系呢?
后面介绍,总之先知道要达到最大的采样率就需要设置我们的时钟


以下正文

那么就让我开始来配置RCC吧!
No.1
首先我们应该用外部接的8MHz晶振来做时钟源。外部高速晶振:HSE;内部高速晶振:HSI
void RCC_HSEConfig(u32 RCC_HSE) 这个函数来启动,内部参数设置 RCC_HSE_ON

RCC_HSEConfig(RCC_HSE_ON);//开启8MHz外部晶振

然后检测外部高速晶振是否正常启动
RCC_WaitForHSEStartUp(); 这个函数, 这个函数返回 SUCCESS 这个参数则代表正常启动

ErrorStatus HSEStartUpStatus;//设置标志位
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)//若外部晶振正常启动
{
/* Add here PLL ans system clock config */
}

这时候我们要通过PLL锁相环来使 外部接的晶振作为输入,输出另一个稳定频率的时钟信号
即我们要用PLL来进行倍频
这里我们设置PLL输出 = 8MHz * 7 = 56MHz (那就是要进行7倍频)

//RCC_PLLSource_HSE_Div1 意思是 PLL的输入时钟 = HSE时钟频率
//RCC_PLLMul_7 表示 7倍频
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);

然后输出

RCC_PLLCmd(ENABLE);//PLL输出使能
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL输出

到目前为止我们得到一个56MHz的时钟频率


No.2
然后我们要利用PLL输出的这个频率作为我们STM32的系统时钟

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//设置系统时钟为56MHz
while(0x08 != RCC_GetSYSCLKSource());//等待系统时钟被正确设置

这样系统时钟就被我们设置好了
接下来的任务就是要设置AHB时钟了
what?AHB时钟又是个啥?
AHB(Advanced High performance Bus)高级高性能总线 或者我们叫它 系统总线
就是我们要设置STM32内部总线的时钟频率
而且AHB又有高低速之分,也就是说我们要设置两个时钟分别给高速AHB低速AHB
AHB掌管着DMA时钟,SRAM时钟和FLITF时钟,它并不直接管ADC的时钟,那我们为什么还要设置它呢?先别急,往下看

RCC_HCLKConfig(RCC_SYSCLK_Div1);//设置AHB时钟(HCLK)
RCC_PCLK2Config(RCC_HCLK_Div1);//设置高速AHB时钟 PLCK2为56MHz (最大72MHz)
RCC_PCLK1Config(RCC_HCLK_Div2);//设置低速AHB时钟 PLCK1为28MHz (最大36MHz)
//注:这里面Div1表示一倍分频,也就是不分频。 PLCK2 = HCLK = 56MHz
//Div2表示2倍分频 PLCK1 = HCLK / 2 = 28MHz

总线设置好了我们就终于可以开始设置ADC的时钟频率了
但这里又要提到一个名词APB
APB(Advanced Peripheral Bus)外围总线
这个才是直接管ADC时钟的总线,APB又分APB1APB2
APB1管TIMx (x = 2, 3, 4 ……) WWDG,SPI2, USART2, USAT3, I2C, CAN的时钟
APB2管TIM1, GPIOx, ADC1, ADC2, SPI1, USART1的时钟
很明显我们只需要对APB2的ADC功能进行设置就行

//使能ADC & GPIOA
//这里我用ADC1采样,PA0端口,具体看各个芯片的数据手册
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);

重点来了

现在来设置ADC了!!!
来上函数 void ADC_ADCCLKConfig(u32 RCC_ADCCLKSource)
看看这个参数 RCC_ADCCLKSource: 定义ADCCLK,该时钟源自APB2时钟(PCLK2)
懂了吧,为啥非要对AHB进行设置,ADC的时钟来源于AHBPLCK2

//RCC_PCLK2_Div4 意思是 ADC时钟 = PCLK2 / 4 = 14MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div4);//ADC最大时钟频率是14MHz

至此,我们就对ADC时钟设置完了,一般来说,我们的STM32系统时钟都是设置的是72MHz,但这里我们为什么非要费那么老劲来设置RCC呢?还是上面这个函数,它的参数一共就4个
Div2 Div4 Div6 Div8 也就是2 4 6 8 分频。
72MHz并不能通过这四个分频得到14MHz最大时钟,所以我们特地设置56MHz,通过4分频,产生14MHz的ADC最大时钟频率。72MHz最大能做到 72 / 6 = 12MHz

来吧,上一份完整的RCC代码

static void RCC_ConfigInitail()
{
	ErrorStatus HSEStartUpStatus;
	FlagStatus Status;
	
	//RCC配置
	RCC_DeInit();//重置
	RCC_HSEConfig(RCC_HSE_ON);//外部8MHz晶振启动!
	HSEStartUpStatus = RCC_WaitForHSEStartUp();
	if(SUCCESS == HSEStartUpStatus)//若启动成功
	{
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);//56MHz PLL输出
		RCC_PLLCmd(ENABLE);//PLL输出使能
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL输出成功	
		
		//设置系统时钟56MHz
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		while(0x08 != RCC_GetSYSCLKSource());//等待设置成功		
		
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
		RCC_PCLK2Config(RCC_HCLK_Div1);//PLCK2 56MHz
		RCC_PCLK1Config(RCC_HCLK_Div2);//PLCK1 28MHz 
		//使能APB2外设时钟 ADC & GPIOA
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
		RCC_ADCCLKConfig(RCC_PCLK2_Div4);//ADC1时钟频率 14MHz
	}
}

等有时间再更新后面的
2018 / 4 / 4 更新……

我是分割线


好了,我们现在来说一说ADC的配置吧
ADC的配置就没什么值得说的,它没有定时器难理解
直接上代码,注释就是解释

ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

//GPIO配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//GPIO采用模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//对PA0初始化
//因为我使用的是ADC1_IN0就是通道0,而这对应STM32C8T6的PA0口
//对于其它型号的要具体看芯片手册

//ADC配置
ADC_DeInit(ADC1);//重置

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC1和ADC2单独工作,互不影响
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//ADC单次采样,即采样一次就停止
ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//ADC单通道采样(ENABLE是多通道扫描)
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发ADC
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;//ADC通道转换数目,我们只用一个ADC,那么就是1
//对于多通道采集才使这个值 >= 2, 取值范围是1~16

ADC_Init(ADC1,&ADC_InitStructure);//初始化
ADC_Cmd(ADC1, ENABLE);//使能

//ADC校准
ADC_ResetCalibration(ADC1);//重置ADC校准器
while(ADC_GetResetCalibrationStatus(ADC1));//等待重置结束

ADC_StartCalibration(ADC1);//开始校准
while(ADC_GetCalibrationStatus(ADC1));//等待校准完成

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);

最后一句话是重点
这句话是重点,看函数名就知道是对ADC通道配置的
这里我们就用一个通道,所以就只写一句,如果有多通道,那么就多写几句,参数变一下即可
要知道ADC转换周期是12.5个ADC时钟周期 而ADC_SampleTime_1Cycles5就是ADC采样时间为
1.5个周期,所以一共12.5 + 1.5 = 14个周期
14MHz / 14 = 1MHz,这样我们就能得到1MHz最大的采样率了
除了1.5以为,STM固件库还给出了其它的一些稀奇古怪的周期
例如:
7.5
13.5
28.5
41.5
55.5
71.5
239.5

呐,就这,ADC最基本的应用就配置完成了
剩下的就是些不痛不痒的代码了

static u16 Get_ADC_Value()
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件启动,ADC开始转换
	while(ADC_GetSoftwareStartConvStatus(ADC1));//等待转换完成
	return ADC_GetConversionValue(ADC1);//返回得到的ADC值
}

到目前为止ADC的最简单的配置就完成了
下面是我个人的情况,可以选择性阅读
下面是我实力分析为什么在高采样率的情况下,上面这些普通的代码不适合测AC交流


这么说吧,这是我一开始写的代码,目的是为了采集交流信号(这不废话么)
要求是测得10HZ ~ 100KHZ的交流信号的有效值
于是我想采用计算真.有效值的方法进行计算
真.有效值的计算公式是
sqrt( 1/T * ∫ f(x)² dt ) (积分区间是0 ~ T)
将之变成离散的信号处理,那么公式就又积分变到求和
sqrt( 1/n * ∑ f(x)² )(求和的话,那就是从0 ~ n)

那么也就是说我需要采样,一个周期采样n个点,n越多,计算得到的真有效值就越接近真值,跟做个示波器差不多了

如此一来我写了如下的程序

//times表示一个周期采样的个数,即上面说的n
float Get_ADC_EffectiveValue(u8 times)
{
	float sum = 0.0;//∑ f(x)² 
	float temp = 0.0;//得到返回的ADC值
	u8 t = 0;
	for(t = 0; t < times; t++)
	{
		//12位采样(0xFFF = 4096),STM32是3.3V供电
		//所以 3.3 / 0xFFF ≈ 0.000805664
		temp = (Get_ADC_Value() - 2048) * 0.000805664f;
		sum += temp * temp;
	}
	
	return (float)sqrt(sum / times);
}

这里我是通过电路将AC信号控制在0 ~ 3.3V,也就是原本的AC信号加上一个DC直流偏置
直流偏置 = VCC / 2,所以我要Get_ADC_Value()之后减去直流偏置,得到原来真实的量

这里再补充一个小细节,再0.000805664后加上个f,意思是告诉CPU这是一个float型常量,别给我弄成个double型了,因为STM32是32位CPU,那么也就是说在32位以下的数据计算速度都差不多。
float占4个字节(32位),double占8个字节(64位),很明显处理float要比double快多了,以后建议能用float就尽量用float

那么好了,我的具体方案是这样的,通过TIM的输入捕获功能来捕捉到信号的上升沿,在通过计算差值得到周期T,我一共捕捉11个上升沿,这样我就得到了10个周期,求平均值后使误差减小
然后ADC开始采样,根据得到的周期来确定一个周期我要采样几个点,就这样
然而后面我发现一系列问题,导致我现在否定了这个方案。

来,我们来分析分析

while(1)
{
	反复分析;//2333333
}

首先我们的定时计数器是工作在56MHz下的,我设置的可计数值为65535,不分频
那么有可能这个周期比较长,我计数器在从0计数到65535后,还没捕捉到第二个上升沿,那么我的这个计数器就会溢出。不要紧,我设置一个全局变量u8 OverFlow = 0;//记录溢出次数
每当我的计数器溢出的话,OverFlow ++;

我计数的Counter = f_TIM / f_IN
f_TIM表示计数器频率即56MHz,f_IN表示输入信号的频率
假如输入信号频率f_IN = 100KHz,那么Counter = 560,嗯,没什么问题
假如f_IN = 10Hz,那么Counter = 5.6 * 1e6,这个可以么?不会太大么?
OverFlow 最大计数255,所以最大Counter = 255 * 65536,这么看有点看不出来,不是很直观
反过来求一下5.6 * 1e6 / 65536 后向下取整为85,也就是说OverFlow 最大只会计数到85,也不是问题
也有人会问,中断不管么?有时间误差啊!
管什么?最多85 + 1次中断,+1是因为捕获到上升沿。急什么,忽略这个时间误差

假如我只知道f_IN,我想知道我的f_TIM应该设置多少?
这样,我们假设Counter >= 100, 那么我计数器从0计数到1的时间间隔t = T_IN / Counter
也就是最小误差(仪器误差)t <= T_IN /100,嗯,1%不到的误差,可以忽略了。
结论一:即当Counter >= 100 时,可以忽略计算周期的误差
那么我就取Counter >= 100
所以f_TIM >= 100 * f_IN,STM32最大72M时钟频率,所以理论上能精确计算的最大输入信号周期的为720KHz。当然,这不是绝对的,你可以通过输入捕获预分频,来扩大这个值,误差还是 1 / Counter这里我们不做过多讨论

由于我们的Counter最小为560,所以根据结论一 可知,一个周期下,输入捕获计算周期的误差忽略,再加上我还通过取平均来减小误差,使得计算得到的误差更小了
结论二:输入捕获计算周期的误差可以忽略不计,不需要管输入捕获了

接下来我们来分析ADC
(嘿嘿嘿!好玩的来了!)

我们得到了输入信号的周期T后,就可以计算一个周期下,ADC采样的次数了
设一个周期内,ADC采样次数为n
则有n = f_ADC / f_IN
f_ADC为ADC的采样频率,f_IN为信号输入频率
那么我们还采用刚才的思路看看,已知f_IN,取n >= 100
则 f_ADC >= 100 * f_IN
确实,前面说过,n越大,越接近积分得到的结果
但是!!!CPU计算也需要时间啊
看看这段代码

	for(t = 0; t < times; t++)// 2n
	{
		temp = (Get_ADC_Value() - 2048) * 0.000805664f;// 3n
		sum += temp * temp;// 3n
	}

这时候我们就不得不计算程序的时间复杂度了
我就假设+ - * / 都是一样的计算时间,都是一个执行周期(真正的情况下乘除要比加减慢,更不要说你根本不知道编译器翻译成汇编之后会有多少条指令,我这么算算是少的)
t < times 需要n次判断
t++需要n次计算
我就假设Get_ADC_Value()得到值后存入内存不要时间
Get_ADC_Value() - 2048需要n次计算

  • 0.000805664f需要n次计算
    赋值到temp需要n次计算
    temp * temp需要n次计算
    sum + (temp * temp)需要n次计算
    赋值到sum需要n次计算
    呵呵,一共是8n的时间复杂度

ARM3官方给出的平均计算速度是1.25MIPS/MHz
意思是1MHz频率下,每秒执行1.25M条指令。我们是56MHz主频,那么就是每秒56M * 1.25条指令
执行一条指令需要 1 / (56 * 1.25 * 1e6)
也就是说光是用在计算上的时间就需要
t = 8n / (56 * 1.25 * 1e6) ≈ 0.114n (单位us)
我们来看看n取100时候的情况
t = 11.4us, 而对于100KHz信号来说,100KHz = 10us,呵呵,光计算的时间就差了一个周期!!
对于10KHz的信号也会有10%的误差
只有1KHz以下的信号才不会收到影响…………
连采集到的信号都不对,谈什么求和逼近积分……做梦吧,梦里啥都有……
结论三:普通方法不能求得1KHz以上信号的准确 真有效值
正所谓鱼和熊掌不可兼得……

但天无绝人之路,我还有DMA!!!意不意外,惊不惊喜!没想到吧!(此处自动脑补表情包)

可是我现在还不会……等我学会了再回来更新,就酱,如果本文对你有收获,想收藏就收藏,想点赞就点赞
未经允许,不得转载,谢谢
未经允许,不得转载,谢谢
未经允许,不得转载,谢谢
重要的事情说三遍!!!


2022 / 5 / 24 (突然 )更新……

(看我自己以前写的文章,感觉自己多少有点犯病,继续犯病ing)

前言

  • 关于上文提到的测有效值的讨论,真有效值计算起来多少有些麻烦,但是利用ADC+DMA还是可以做到的,但是我也没再管过。最多用到AD637这块芯片测有效值,虽然不是真有效值,但应付毕设,课设还行,把复杂的事交给专业的吧,开摆!
  • 最近重新捡起STM32,但是没有再用过keil了,而是用起了STM32CubeIDE,利用stm32cubeMX生成基础代码,省去基础配置时间,专心开发应用就行。而且也没再使用过std库了,HAL库确实很香。
  • 下面介绍ADC连续采样+DMA双缓冲,实现DAC生成正弦波,ADC采样,并将波形回传至PC并绘制出来。其中DAC也使用了DMA功能,本篇不介绍(挖坑
  • 硬件开发平台STM32F407ZET6开发板,时钟频率168MHz,APB1 Timer CLK:84MHz,APB2 Timer CLK:168MHz

预备知识

如果你没有接触过HAL库,那么下面有些词可能听的云里雾里的,这里做一个简单的说明

  • 回调函数:对于一个函数A,我将函数B的函数指针(这个指针指向函数)做为参数传入到函数A中,那么我们称函数B是一个回调函数(Call Back Function)。这样我可以设置不同的回调函数B1,B2,B3……这意味着函数A对不同的函数Bx做出了相同的操作,因此才将其封装起来。当我需要的时候,我只需要传入不同的参数B1,B2,B3……就可以完成不同的操作。在HAL库中,我们往往要编写中断回调函数。当发生中断时,库函数会帮我们判断发生了什么中断,并完成清除标志位等操作,然后调用不同的中断回调函数(HAL_xxxCallback(…)),这些回调函数都是__weak函数,等待用户编写内容。
  • __weak函数(弱函数):__weak关键字用来修饰函数或者变量,表示修饰的函数或变量的使用优先级较低。如果我们定义了一个函数或变量,它与关键字__weak修饰的函数或者变量名一致,则优先使用我们定义的,而忽略__weak修饰的。举个例子:
__weak int FuncCallback(int a, int b)
{
	//do nothing
	return 0;
}

//如果我们不重新定义这个函数,那么编译器就会默认使用上面的那个__weak函数
//但如果我们重新定义了FuncCallback这个函数,那么编译器就会使用我们的
int FuncCallback(int a, int b)
{
	//user code
	return a + b;
}

void UserFunc(void)
{
	int a = 2, b = 3;
	int retval;
	retval = FuncCallback(a, b);//2+3=5
}

DMA简介

DMA的传输数据不占用CPU,是外设(例如ADC或者DAC)到内存、内存到外设、内存到内存的一种传输数据手段。以ADC为例,当ADC转换完成后,由ADC向CPU发出DMA请求,CPU将总线权交给DMA,由DMA控制器将数据搬运到内存中,此时CPU可以干其它事情。等到DMA将一组数据搬运完成之后,我们就可以在中断函数里对数据做处理。
假如我们要计算真有效值,我们可以使用DMA先传输一组数据X1,然后CPU对数据X1做运算的同时,DMA开始接收下一组数据X2,等到X2接收完毕,CPU就可以对X2做处理。

DMA双缓冲

所谓的DMA双缓冲,即一个外设对应两个内存地址,记A和B两个内存地址,当从外设传输完一组数据到A内存后,CPU可以对此内存进行操作,同时开启外设到B内存的数据传输,反过来从内存到外设也是一样的,只是传输数据方向不同。这样CPU对内存的操作和DMA传输数据的操作就可以同时进行。
但是基于HAL库的cubeMX生成的代码对DMA双缓冲的支持并不好,相关的回调函数更是没有定义,用户需要自己设置。但这并不意味着没法实现DMA双缓冲,原因就在于HAL库有大量的HAL_xxxHalfCpltCallback()函数(传输一半回调函数——Half Complete Call Back)
如果我们使用第一种方法,那么我们需要定义两个数组A[10], B[10],假设长度都是10,那么也就是说,每当DMA传输10个数据到A或者B后,DMA会产生一个中断,CPU就可以处理这10个数据了。假如我们使用第二种方法,我们只需要定义数组C[20],那么当DMA传输完成一半的时候,也会有个中断,我们同样可以数据处理,开销是一样的。

ADC & DMA配置

  • ADC单通道连续采样
  • 12bits,数据右对齐
  • 由软件触发(还可以设置为某些TIM的捕获/比较事件)
  • DMA传输方向:由外设到内存,内存地址自动递增
  • DMA模式:循环模式。即传输完一组数据后,内存地址重置,从头开始,覆盖原来的数据
  • DMA传输数据宽度:半字(Half Word = 2 Byte = 16 bit)
  • 采用DMA双缓冲,DMA一边传输数据,CPU一边将数据通过串口发送到PC,由PC绘制波形

具体配置如下图
在这里插入图片描述
DMA设置如下(使用DMA的时候,cubeMX强制开启对应中断,如有必要,用户在NVIC中配置优先级即可)
在这里插入图片描述
代码配置如下

//File adc.c
……
extern uint16_t ADC_RX_BUF[100];//以100个数据为一组
/* USER CODE BEGIN 1 */

//DMA半传输完成回调函数
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
	uint8_t i;
	if(hadc->Instance == ADC1)
	{
		for(i = 0; i < 50; i++)//处理一半数据
		{
			printf("$%.5f;\n", 3.3 * ADC_RX_BUF[i] / 4095);//发送数据到pc,上位机将数据绘制出来,波特兰设置为460800
		}
	}
}

//DMA传输完成回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	uint8_t i;
	if(hadc->Instance == ADC1)
	{
		for(i = 50; i < 100; i++)//处理另一半数据
		{
			printf("$%.5f;\n", 3.3 * ADC_RX_BUF[i] / 4095);
		}
	}
}
/* USER CODE END 1 */
……
//File main.c
……
uint16_t ADC_RX_BUF[100];

int main(void)
{
	//启动ADC,使能DMA,数据长度为100
	HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_RX_BUF, 100);
	while(1)
	{
	}
}
……

实验结果如下
上位机

  • 50
    点赞
  • 162
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
AD7606是一款16通道16位高精度模数转换器,可以实现同时采集多个模拟信号并将其转换为数字信号,而STM32是一款广泛应用于嵌入式系统的微控制器,它拥有高性能和低功耗的特性,因此AD7606和STM32的结合非常适合需要高精度数据采集的场合。接下来我们将详细介绍AD7606和STM32的连接图,以便读者能够更好地理解它们之间的关系。 首先,AD7606有多个引脚,包括16个模拟输入通道、4个控制引脚和一个时钟引脚。此外,AD7606还有一个串行接口,可以将数字信号输出到外部设备中。对于STM32,它也具有多个引脚,包括用于控制和数据传输的引脚。 在连接图中,我们可以看到AD7606的每个引脚都与STM32的一个引脚相连接。具体来说,AD7606的模拟输入通道连接到STM32的模拟输入引脚,控制引脚连接到STM32的控制引脚,时钟引脚连接到STM32的时钟引脚,而数字输出连接到STM32的数字引脚。 需要注意的是,在AD7606和STM32之间的连接中,还需要一个电源引脚。在这种情况下,我们可以选择使用一个共同的电源来为它们供电,或者使用独立的电源为它们分别供电。无论采用何种供电方式,都需要确保AD7606和STM32的电源稳定以及电压兼容。 总之,AD7606和STM32的连接图非常简单,只需要将它们的引脚相连即可。当然,在实际应用中,我们还需要编写相应的程序来控制AD7606和处理采集到的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值