工程笔记阶段1-DAC正弦波实验

本文详细介绍了如何使用STM32的DAC模块配合定时器和DMA技术,实现干扰电治疗仪中正弦波的输出。涉及设备原理、DAC初始化、正弦波数据制作、下位机编程等步骤,并提供了关键代码片段。适合嵌入式开发者学习DAC应用。
摘要由CSDN通过智能技术生成


前言

近期准备升级干扰电治疗仪,对于前期的准备工作做一个简单的汇总和梳理,文章中可能会有不正确的说法,仅供参考。

一、干扰电简介

1.适应症

干扰电疗法适用于神经炎、神经痛、神经根炎、肌萎缩、扭伤、肩周炎、肌纤维鞘炎、肌劳损、关节炎、雷诺病、手足发绀症、胃下垂、习惯性便秘等。

2.禁忌症

急性化脓性炎症,有出血倾向,局部有金属固定物,体内植入心脏起搏器者。

3.操作

将选好之两组电极妥善固定于治疗部位,并使两组电流交叉在病灶处。治疗电极有衬垫电极、手套电极及抽吸电极3种,可按医嘱选用。

4.用法举例1

腰骶神经根炎治疗法 将一组面积为30~50cm衬垫电极分别置于左下及右上腰骶部,另一组同等面积电极分别置于右下及左上腰骶部。定频输出90Hz,变频输出90~100Hz,各治疗10min,1/d。

5.用法举例2

胃下垂治疗法 将一组面积为 100cm电极分别置于左腹及右腰部,另一组同等面积衬垫电极置于右腹及左腰部。定频输出1~5Hz,变频输出40—100Hz,各10min,1/d。

6.注意事项

①两组电极不得互相接触,衬垫应湿透并紧密接触皮肤。衬垫勿置于皮肤破损处。
②电流不可穿过心脏、脑、孕妇下腹部。
③有金属异物的局部,不可进行此种疗法。

7.原理

①是频率为4000±100Hz的正弦电流。治疗时用四个电极,将两路频率相差100Hz的中频率交流电(一路频率固定4000Hz,另一路为4000±100Hz,其频率可每15秒变动一次,变动范围可调)交叉地输入人体,在机体深部产生一个差频电流。
②在电极下输入时是中频,交叉干扰后就将得0~100Hz的低频,这种低频不是外界输入,而是内部产生的,且还含有中频的成份。这种深处“内生”的低频调制的脉冲频电刺激克服了低频电流不能深入组织内部的缺陷,且可应用较大的电流强度。这是干扰电疗法最突出的特点,所以它兼有中频和低频电疗的特点。
③仪器工作过程中无化学反应(无电解作用),电极可简化,操作较简便。

二、知识梳理

1.设备原理

通过百度可以发现干扰电疗法的主要原理为驱动mcu产生正弦波,推测主要运用DAC功能,在这个基础上增加人机交互,如参数的显示、调整。由于博主主要负责嵌入式软件,目前阶段在此主要记录DAC的软件相关知识点。

2.DAC简介

(1)框图

在这里插入图片描述

(2)DAC的功能

DAC 为数字/模拟转换模块,故名思议,它的作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与 ADC 相反。在常见的数字信号系统中,大部分传感器信号被化成电压信号,而 ADC 把电压模拟信号转换成易于计算机存储、处理的数字编码, 由计算机处理完成后,再由 DAC 输出电压模拟信号,该电压模拟信号常常用来驱动某些 执行器件,使人类易于感知。如音频信号的采集及还原就是这样一个过程。

(3)STM32的DAC特点

STM32 具有片上 DAC 外设,它的分辨率可配置为 8 位或 12 位的数字输入信号,具有 两个 DAC 输出通道,这两个通道互不影响,每个通道都可以使用 DMA 功能,都具有出错检测能力,可外部触发。

(4)参考电压

与 ADC 外设类似,DAC 也使用 VREF+引脚作为参考电压,在设计原理图的时候一般把 VSSA接地,把 VREF+和 VDDA 接 3.3V,可得到 DAC 的输出电压范围为:0~3.3V。
如果想让输出的电压范围变宽,可以在外部加一个电压调理电路,把 0~3.3V 的 DAC 输出抬升到特定的范围即可

(5)数模转换及输出通道

框图中的数字至模拟转换器 x是核心部件,整个 DAC 外设都围绕它而展开。它以左边的 VREF+作为参考电源,以 DAC 的数据寄存器“DORx”的数字编码作为输入,经过它转换得的模拟信号由右侧的“DAC_OUTx”通道输出。其中各个部件中的x是指设备的标号,在 STM32 中具有 2 个这样的 DAC 部件,每个DAC有1个对应的输出通道连接到特定的引脚,即:PA4-通道 1,PA5-通道 2,为避免干扰,使用 DAC 功能时,DAC 通道引脚需要被配置成模拟输入功能(AIN)。

(6)触发源及 DHRx 寄存器

在使用 DAC 时,不能直接对上述 DORx 寄存器写入数据,任何输出到 DAC 通道 x 的数据都必须写入到 DHRx 寄存器中(其中包含 DHR8Rx、DHR12Lx 等,根据数据对齐方向和分辨率的情况写入到对应的寄存器中)。也就是说我们准备好的正弦波数组要填入这个寄存器当中。
数据被写入到 DHRx 寄存器后,DAC 会根据触发配置进行处理,若使用硬件触发,则 DHRx 中的数据会在 3 个 APB1 时钟周期后传输至 DORx,DORx 随之输出相应的模拟电压到输出通道;若 DAC 设置为外部事件触发,可以使用定时器(TIMx_TRGO)、EXTI_9 信号或软件触发(SWTRIGx)这几种方式控制数据 DAC 转换的时机,例如使用定时器触 发,配合不同时刻的 DHRx 数据,就可以实现 DAC 输出正弦波的功能。

3.DAC 初始化结构体

(1)结构体DAC_InitTypeDef

DAC 相关的各种配置封装到了结构体 DAC_InitTypeDef 中, 它主要包含了 DAC_CR 控制寄存器的各寄存器位的配置。

1)typedef struct
2){
3)	/*DAC 触发方式 */
4)	uint32_t DAC_Trigger;           
5)	/*是否自动输出噪声或三角波 */
6)	uint32_t DAC_WaveGeneration;      
7)	/*选择噪声生成器的低通滤波或三角波的幅值 */
8)	uint32_t DAC_LFSRUnmask_TriangleAmplitude; 
9)	/*选择是否使能输出缓冲器 */
10)	uint32_t DAC_OutputBuffer;          
11)}DAC_InitTypeDef;

(2)成员DAC_Trigger

本成员用于配置 DAC 的触发模式,当 DAC 产生相应的触发事件时,才会把 DHRx 寄 存器的值转移到 DORx 寄存器中进行转换。本结构体成员可以选择的触发模式如下:
1.硬件触发(DAC_Trigger_None),DHRx 寄存器内的数据会在 3 个 APB1 时钟周期内自动转换到DORx 进 行 转 换 ;
2.定时器触发模式(DAC_Trigger_T2/4/5/6/7_TRGO),使用定时器 2、4、5、6、7 控制 DHRx 寄存器的数据按时间转移到 DORx 中进行转换,利用这种方式可以输出特定的波形;
3.EXTI_9 触发方式(DAC_Trigger_Ext_IT9),当产生 EXTI_9 事件时(如 GPIO 中断事件), 触发转换 ;
4.软件 触发模式( DAC_Trigger_Software ),在本模式下, 向 DAC_SWTRIGR 寄存器写入配置即可触发信号进行转换。

(3)成员DAC_WaveGeneration

本成员用于设置是否使用 DAC 输出伪噪声或三角波(DAC_WaveGeneration_None/Noise/Triangle),使用伪噪声和三角波输出时,DAC 都会把 LFSR 寄存器的值叠加到 DHRx 数值上,产生伪噪声和三角波,若希望产生自定义的输出时,直接配置为 DAC_WaveGeneration_None 即可。

(4)成员DAC_LFSRUnmask_TriangleAmplitude

本成员通过控制 DAC_CR 的 MAMP2 位设置 LFSR 寄存器位的数据,即当使用伪噪声或三角波输出时要叠加到 DHRx 的值,非噪声和非三角波输出模式下,本配置无效。使用伪噪声输出时LFSR=0xAAA,MAMP2 寄存器位可以屏蔽 LFSR 的某些位,这时把本结构体成员赋值为DAC_LFSRUnmask_Bit0~DAC_LFSRUnmask_Bit11_0 等宏即可; 使用三角波输出时, 本结构体设置三角波的最大幅值 , 可选择为 DAC_TriangleAmplitude_1~ DAC_TriangleAmplitude_4096 等宏,DAC 在 DHRx 值的基础上升,幅值达到 MAMPx 设置的最大幅度时下降,形成三角波的输出。

在这里插入图片描述

(5)成员DAC_OutputBuffer

本结构体成员用于控制是否使能 DAC 的输出缓冲 (DAC_OutputBuffer_Enable/Disable),使能了 DAC 的输出缓冲后可以减小输出阻抗, 适合直接驱动一些外部负载。

4.DAC 输出正弦波实验

(1)方法

DAC 配合 TIM 定时器,可以输出随时间变化的电压如正弦波。

(2)编程要点

1)计算获取正弦波数据表;
2)根据正弦波数据表的周期内点数和周期计算定时器触发间隔;
3)初始化 DAC 输出通道,初始化 DAC 工作模式;
4)配置触发 DAC 用的定时器;
5)配置 DMA 自动转运正弦波数据表。

(3)正弦波与寄存器的关系

要输出正弦波,实质是要控制 DAC 以 v=sin(t) 的正弦函数关系输出电压,其中 v 为电压输出,t 为时间。而由于模拟信号连续而数字信号是离散的,所以使用 DAC 产生正弦波时,只能按一定时间间隔输出正弦曲线上的点,在该时间段内输出相同的电压值,若缩短时间间隔,提高单个周期内的输出点数,可以得到逼近连续正弦波的图形,若在外部电路加上适当的电容滤波,可得到更完美的图形。
上图为32个点,下图为128个点。
在这里插入图片描述
在这里插入图片描述
由于正弦曲线是周期函数,所以只需要得到单个周期内的数据后按周期重复即可,而单个周期内取样输出的点数又是有限的,所以为了得到呈 v=sin(t) 函数关系电压值的数据通常不会实时计算获取,而是预先计算好函数单个周期内的电压数据表,并且转化成以 DAC 寄存器表示的值。

(4)输出的转换

在这里插入图片描述

如图 sin 函数值的范围为[-1: +1],而 STM32 的 DAC 输出电压范围为[0~3.3]V,按12位 DAC 分辨率表示的方法,可写入寄存器的最大值为 2^12 = 4096,即范围为[0:4096]。所以实际输出时,会进行如下处理:

a.抬升 sin 函数的输出为正值:v = sin(t)+1 ,此时,v 的输出范围为[0:2];

b.扩展输出至 DAC 的全电压范围: v = 3.3*(sin(t)+1)/2 ,此时,v 的输出范围为[0:3.3], 正是 DAC 的电压输出范围,扩展至全电压范围可以充分利用 DAC 的分辨率;

c.把电压值以 DAC 寄存器的形式表示:Reg_val = 2^12/3.3 * v = 2^11*(sin(t)+1),此时,存储到 DAC 寄存器的值范围为[0:4096];

d.在 sin(t)的单个周期内,取 32 个点进行电压输出已经能较好地还原正弦波 形,所以在 t∈[0:2π]区间内等间距根据上述 Reg_val 公式运算得到 32 个寄存器值, 即可得到正弦波表;

e.控制 DAC 输出时,每隔一段相同的时间从上述正弦波表中取出一个新数据进行输出, 即可输出正弦波。改变间隔时间的单位长度,可以改变正弦波曲线的周期。

(5)通过python制作正弦波数据表

我使用的python3.7,因为需要显示图像和计算,还需要安装两个外部库
1)安装matplotlib库
a.Win+R输入cmd进入到CMD窗口下,执行python-m pip install -U pip setuptools进行升级。

b.输入python -m pip install matplotlib进行自动的安装,系统会自动下载安装包(因为网络问题可能会报错,多试几次即可)

c.进入到python idle中,运行import matplotlib,如果没有报错,就证明安装完成。
在这里插入图片描述
2)安装numpy库
a.Win+R输入cmd进入到CMD窗口下,执行pip3 install numpy scipy matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

b.进入到python idle中,运行from numpy import *,再运行eye(4),出现如下结果就证明安装成功。
在这里插入图片描述
3)运行程序获取正弦波数据表

"""
运行结果:
命令行中会打印计算得的各点数据,
在当前目录下会生成py_dac_sinWav.c文件,包含上述数据,
并且会弹出描绘曲线的对话框。
"""

import matplotlib.pyplot as plt 
import numpy as np
import math

#修改本变量可以更改点数,如16、32、64等
POINT_NUM = 32

pi = math.pi

#一个周期 POINT_NUM 个点,n是周期内x轴点的集合
n = np.linspace(0,2*pi,POINT_NUM)

#计算POINT_NUM个点的正弦值,a是周期内y轴点的集合
a = map(math.sin,n)


r =[]
#对y进行转换
for i in a:
    #调整幅值至在0~2区间
    i+=1       
    
    #按3.3V电压调整幅值
    i*= 3.3/2   

    #求取dac数值,12位dac LSB = 3.3V/2**12 
    ri = round(i*2**12/3.3) 

    #检查参数
    if ri >= 4095:
        ri = 4095

    #得到dac数值序列
    r.append( ri )


print(list(map(int,r)))

#写入序列到文件
with open("py_dac_sinWav.c",'w',encoding= 'gb2312') as f:
    print(list(map(int,r)),file= f)

#绘图
plt.plot(n,r,"-o")
plt.show()

a.Python 脚本的实现原理就是前面介绍的正弦波数据表的制作过程,运行后,该脚本把 得到的正弦波表数据输出到目录下的 py_dac_sinWav.c 文件中

b.代码生成的正弦波数据表
[2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668, 3382, 3042, 2661, 2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127, 310, 564, 878, 1240, 1636, 2048]

c.代码描绘的曲线图
在这里插入图片描述

(6)下位机程序的编写

①创建dac.h,设置好相关的宏定义,添加如下代码

//DAC DHR12RD寄存器,12位、右对齐、双通道
#define DAC_DHR12RD_ADDRESS      (DAC_BASE+0x20) 

此处定义的宏 DAC_DHR12RD_ ADDRESS 是寄存器 DHR12RD 的地址,该寄存器是 12 位右对齐的双通道寄存器,在本实验中将会使用 DMA 把正弦波数据表的点数据赋值到该寄存器中,往该寄存器赋值后的数据会在 DAC 被触发的时候搬运到 2 个 DAC 转换器,然后在这 2 个通道中输出,以 12 位右对齐的数据表示的这两个通道的电压。与 DAC 控制相关的引脚固定是 PA4 和 PA5,就不使用宏定义了,在代码中直接使用引脚号操作。
在这里插入图片描述

②创建dac.c,添加如下代码完成DAC GPIO 和模式配置

static void DAC_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef  DAC_InitStructure;

  /* 使能GPIOA时钟 */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
	
	/* 使能DAC时钟 */	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
	
  /* DAC的GPIO配置,模拟输入 */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	


  /* 配置DAC 通道1 */
  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;						//使用TIM2作为触发源
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;	//不使用波形发生器
  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;	//不使用DAC输出缓冲
  DAC_Init(DAC_Channel_1, &DAC_InitStructure);

  /* 配置DAC 通道2 */
  DAC_Init(DAC_Channel_2, &DAC_InitStructure);

  /* 使能通道1 由PA4输出 */
  DAC_Cmd(DAC_Channel_1, ENABLE);
  /* 使能通道2 由PA5输出 */
  DAC_Cmd(DAC_Channel_2, ENABLE);

  /* 使能DAC的DMA请求 */
  DAC_DMACmd(DAC_Channel_2, ENABLE);
}

在 DAC_Config 函数中,完成了 DAC 通道的 GPIO 的初始化和 DAC 模式配置。其中 GPIO 按照要求被配置为模拟输入模式(没有模拟输出模式),在该模式下才能正常输出模拟信号。

配置 DAC 工作模式时,则使用了 DAC_InitTypeDef 类型的初始化结构体,把 DAC 通 道 1 和 2 都配置成了使用定时器 TIM2 触发、不使用波形发生器以及不使用 DAC 输出缓冲的模式。

初始化完 GPIO 和 DAC 模式后,还使用了 DAC_Cmd、DAC_DMACmd 函数使能了通道以及 DMA 的请求。由于本实验中对 DAC1 和 2 的操作是同步的,所以只要把 DMA 与 DAC 通道 2 关联起来即可,当使用 DMA 设置通道 2 的数据值时,同时更新通道 1 的内容(DHR12RD寄存器是32位的。给通道2赋值32位的数据,高16位就是通道1的数据)。

③定时器配置及计算正弦波的频率

初始化完 DAC 后,需要配置触发用的定时器,设定每次触发的间隔,以达到控制正 弦波周期的目的。
添加定时器的配置代码

static void DAC_TIM_Config(void)
{
	
	TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;
	
	/* 使能TIM2时钟,TIM2CLK 为72M */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
  /* TIM2基本定时器配置 */
 // TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
  TIM_TimeBaseStructure.TIM_Period = (562-1);       									//定时周期 140  
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;       							//预分频,不分频 72M / (0+1) = 72M
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    						//时钟分频系数
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  	//向上计数模式
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* 配置TIM2触发源 */
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

	/* 使能TIM2 */
  TIM_Cmd(TIM2, ENABLE);

}

因为前面的 DAC 配置了 TIM2 当触发源,所以这里将对 TIM2 进行配置。TIM2 的定时周期被配置为 562,向上计数,不分频。即 TIM2 每隔 562*(1/72M)秒就会触发一次 DAC 事件,作 DAC 触发源使用的定时器并不需要设置中断,当定时器计数器向上计数至指定的值时,产生 Update 事件,同时触发 DAC 把 DHRx 寄存器的数据转移到 DORx,从而开始进行转换。

根据定时器的配置,可推算出正弦波频率的计算方式:
a.STM32 系统时钟周期为1/72000000 (72m)

b.预分频系数选择不分频,定时器2的单个时钟周期依然为1/72000000

c.定时器2的定时周期配置为562,则触发周期为562/72000000

d.根据正弦波单个周期的点数32,求出正弦波单个周期为32*562/72000000

e.正弦波的频率为72000000/562/32=4003.5587,约等于4000,是干扰电疗法所用到4000±100hz频率。

④DMA配置

实验的数据使用DMA搬运,尽量减少对mcu时间的占用,添加DMA配置代码

//正弦波单个周期的点数
#define POINT_NUM 32

/* 波形数据 ---------------------------------------------------------*/
const uint16_t Sine12bit[POINT_NUM] = {
	2048	, 2460	, 2856	, 3218	, 3532	, 3786	, 3969	, 4072	,
	4093	, 4031	, 3887	, 3668	, 3382	, 3042	,	2661	, 2255	, 
	1841	, 1435	, 1054	, 714		, 428		, 209		, 65		, 3			,
	24		, 127		, 310		, 564		, 878		, 1240	, 1636	, 2048
};

uint32_t DualSine12bit[POINT_NUM];

static void DAC_DMA_Config(void)
{	
	DMA_InitTypeDef  DMA_InitStructure;

	/* 使能DMA2时钟 */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
	
	/* 配置DMA2 */
  DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS;					//外设数据地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit ;				//内存数据地址 DualSine12bit
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;											//数据传输方向内存至外设
  DMA_InitStructure.DMA_BufferSize = POINT_NUM;																	//缓存大小为POINT_NUM字节	
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;				//外设数据地址固定	
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;									//内存数据地址自增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;	//外设数据以字为单位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;					//内存数据以字为单位	
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;													//循环模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;											//高DMA通道优先级
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;														//非内存至内存模式	

  DMA_Init(DMA2_Channel4, &DMA_InitStructure);
	
  /* 使能DMA2-14通道 */
  DMA_Cmd(DMA2_Channel4, ENABLE);
}

void DAC_Mode_Init(void)
{
	uint32_t Idx = 0;  

	DAC_Config();
	DAC_TIM_Config();	
	
	/* 填充正弦波形数据,双通道右对齐*/
  for (Idx = 0; Idx < POINT_NUM; Idx++)
  {
    DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx]);
  }
	
	DAC_DMA_Config();
}

在上述代码中 , 定义了由脚本得到的正弦波数据表 Sine12bit 变量 , 一共为 POINT_NUM(32)个点。在 DAC_Mode_Init 函数中,调用了前面介绍的 DAC_Config 和 DAC_TIM_Config 初始化 DAC 和定时器,然后在 for 循环中把单通道的正弦波数据表 Sine12bit 复制扩展成为双通道的DualSine12bit,扩展后的数据将会直接被 DMA 搬运 至 DAC 的 DHR12RD 寄存器中。 [27:16]是通道2的数据,[11:0]是通道1的数据,数组DualSine12bit的每个数据,高16位给通道2,低16位给通道1。

复制完数据后,DAC_Mode_Init 调用下面的 DAC_DMA_Config 函数初始化 DMA,配置的重点是要设置好 DHR12RD 寄存器的地址,正弦波数据的内存地址(注意是双通道数 据 DualSine12bit),DMA 缓存的个数(即单个周期的正弦波点数)以及 DMA 工作在循环模式。

经过这样的配置后,定时器每间隔一定的时间就会触发 DMA 搬运双通道正弦波表的一个数据到 DAC 双通道寄存器进行转换,每完成一个周期后 DMA 重新开始循环,从而达到连续输出波形的目的。

⑤主函数的编写

int main(void)
{
	/*初始化DAC,开始DAC转换*/
	DAC_Mode_Init();
	while(1);	 
}

主函数调用 DAC_Mode_Init完成所有的初始化后就可以通过示波器测量到4000hz左右的正弦波。

⑥验证

在这里插入图片描述
在这里插入图片描述
可以通过增加周期内的正弦点数提升波形质量,下图是一个周期内128个点的波形,需要修改正弦波数组和定时器的周期
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

源代码分享链接

本文主要参考书籍:STM32库开发实战指南,STM32F10x-中文参考手册,相关百度百科
链接:https://pan.baidu.com/s/1EM1ADanuDnwtcWcRrprSfw
提取码:ooha

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值