细说MCU构建两路包含ADC和DAC的测量系统的方法

44 篇文章 0 订阅
42 篇文章 0 订阅

目录

一、参考工程

二 、硬件配置

1.配置GPIO

2.配置ADC1和ADC2

3.配置DAC1和DAC2

4.配置定时器     

5.配置串口 

6.选择时钟源和Debug 

7.配置系统时钟和ADC时钟

三、代码修改

1.定义DAC波形数据

2.重定义外部中断回调函数

3.重定义ADC回调函数

4.初始化 

5.变量声明

6.常量声明

四、查看结果

1.通过示波器观察到的波形

2.通过Time Scope上显示的带谐波的正弦波形

3.通过Time Scope上显示的正弦波形 


一、参考工程

        本文描述的项目依赖本文作者的其他文章:细说MCU构建包含ADC和DAC的测量系统的方法-CSDN博客  https://wenchm.blog.csdn.net/article/details/140815986icon-default.png?t=N7T8https://wenchm.blog.csdn.net/article/details/140815986

        参考文章的例子中,采用了一路ADC测量、一路DAC输出的模拟信号;因为G474板上有多路ADC,所以可以在此基础上增加一路ADC,用两路ADC测量两路DAC输出信号 。还是利用串口送出采样值数据(一个时刻送出一路,用按键B1切换),用Simulink模型看波形。

二 、硬件配置

1.配置GPIO

        用到按键B1(按键连接引脚为PC13)切换串口发送的数据,配置PC13为GPIO_EXTI13,使用外部中断功能,配置参数为上升沿触发,下拉,用户标识命名为KEY;在NVIC设置中选择该中断,并将其优先级设置为1。将tick timer的抢占式优先级设为0。

2.配置ADC1和ADC2

       配置Analog中的ADC。依次选择ADC1,使用ADC1的通道1(IN1)并将其配置为单端模式(IN1 Single-ended)和选择ADC2的通道2,均将其配置为单端模式(IN2 Single-ended)(PA1)。时钟预分频因子均设置为:by 1。

       均添加一个ADC的DMA请求,将其模式设置为循环(Circular)。在增量地址(Increment Address)中,勾选上存储器(Memory),将数据宽度(Data Width)设置为Half Word。采用定时器实现对ADC采样频率的控制,故将ADC设置(ADC_Settings)参数栏中的连续转换模式(Continuous Conversion Mode)设置为Disabled。

        均使能DMA连续请求(DAM Continuous Requests)参数,将其参数选择为Enabled。

        在ADC规则转换模式(ADC_Regular_ConversionMode)栏,均将外部触发转换源(External Trigger Conversion Source)选择为Timer8 Trigger Out event。在ADC规则转换模式 参数栏中,均将Rank下的采样时间选择为2.5个周期。

        其他参数均选择默认。

3.配置DAC1和DAC2

        打开Analog,依次然后选择DAC2和DAC1。均选择Connected to external pin only。Trigger均用Timer 3 Trigger Out event。依次添加DAC2的DMA请求DAC2_CH1和添加DAC1的DMA请求DAC1_CH1,均并设置其模式为Circular,外设(Peripheral)字长为Word,存储器(Memory)字长为Half Word。

4.配置定时器     

        使用TIM3触发DAC,使用TIM8触发ADC。

        打开Timers选择TIM3。在其模式区中将时钟 (Clock Source)选择为内部时钟(Internal Clock),将TIM3的时钟预分频因子设置为169、计数器周期设置为99,则系统时钟为170 MHz ,触发事件选 TRGO设置为Update Event。TIM3的事件更新频率为10 kHz。当一个周期波形内的数据为200点时,DAC输出波形频率即为50 Hz。

        然后,打开TIM8的配置界面,将其模式区中的时钟源(Clock Source)选择为内部时钟 (nternal Clock),预分频因子设置为169,计数器周期设置为99,触发事件选 TRGO设置为Update Event。前两个参数决定着TIM8更新事件的周期,用于控制ADC 采样频率,后一个参数用作ADC采样的触发信号。

5.配置串口 

        打开Connectivity->USART2,其模式(Mode)选择异步(Asynchronous),其他参数设置均保持默认(波特率为10000000 bit/s),不开启中断。将USART2的两个引脚PA2和PA3均设置为上拉(Pull-up)。

6.选择时钟源和Debug 

        打开System Core中的RCC,高速时钟(HSE)选择Crystal/ eramic Resonator,使用片外时钟晶体作为HSE的时钟源。在SYS中将Debug设置Serial Wire。

7.配置系统时钟和ADC时钟

        将系统时钟(SYSCLK)频率配置为170 MHz,并设置ADC1的时钟为34 MHz。

A = 4096/2-1;    %信号幅值
N = 200;		 %一个周期内的数据点数 
Ph = pi/2; 		 %信号1初始相位 
SineData = ceil(A*sin(Ph:2*pi/N:2*pi*(1-1/N)+Ph)+A);	%正弦波
Fid = fopen('SineData.txt','w');
fprintf(Fid,'%d,',SineData);
fclose(Fid);

三、代码修改

在main.c的初始化部分增加启动ADC2和DAC1的库函数,然后重定义外部中断回调函数和ADC回调函数。

1.定义DAC波形数据

        用MATLAB语句产生两路DAC波形数据:一路为50 Hz正弦信号,另外一路为带三次谐波的正弦信号。一个周期的数据点数为200。

         产生正弦波形的MATLAB语句:

A = 4096/2-1;    %信号幅值
N = 200;		 %一个周期内的数据点数 
Ph = 0; 		 %信号1初始相位 
SineData = ceil(A*sin(Ph:2*pi/N:2*pi*(1-1/N)+Ph)+A);	%正弦波
Fid = fopen('SineData.txt','w');
fprintf(Fid,'%d,',SineData);
fclose(Fid);

         带谐波的MATLAB语句详见本文的参考文件。

2.重定义外部中断回调函数

        由于要用到按键B1切换串口发送的数据,所以在中断中设置了一个标志变量SignalFlag (数据类型可定义为uint8_t)。该变量初始为0,每按一次加1,按两次后又赋值为0。 EXTI中断回调函数的定义如下:

3.重定义ADC回调函数

        由于DMA完成一次数据传递后就会调用一次ADC的回调函数,所以仍旧将串口数据发送放到ADC的回调函数中。

        在ADC的回调函数中,首先判断标志变量SignalFlag的值:如果为0,就发送ADC1的采样值数据;如果不为0,则发送ADC2的采样值数据。因为两路ADC共用一个回调函数,所以 在代码中增加了if语句,判断当前进入中断的是哪一路ADC。

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	HAL_Delay(10);
 	if(GPIO_Pin == KEY_Pin)
 	{
 		SignalFlag++;
 		if(SignalFlag == 2)
 			SignalFlag = 0;
 	}
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef*AdcHandle)
{
	if(SignalFlag == 0)
	{
		if(AdcHandle ==(&hadc1))
		{
 			HAL_UART_Transmit(&huart2,(uint8_t *)&FrameHeader,2,0xFFFF);
 			HAL_UART_Transmit(&huart2,(uint8_t *)&ADC1ConvertedData,ADC_CONVERTED_DATA_BUFFER_SIZE*2,0xFFFF);
 			HAL_UART_Transmit(&huart2,(uint8_t*)&FrameTerm,2,0xFFFF);
 		}
 	}
 	else
 	{
 		if(AdcHandle == (&hadc2))
 		{
 			HAL_UART_Transmit(&huart2,(uint8_t*)&FrameHeader,2,0xFFFF);
 			HAL_UART_Transmit(&huart2,(uint8_t*)&ADC2ConvertedData,ADC_CONVERTED_DATA_BUFFER_SIZE*2,0xFFFF);
 			HAL_UART_Transmit(&huart2,(uint8_t*)&FrameTerm,2,0xFFFF);
 		}
 	}
}
/* USER CODE END 4 */

        在ADC的回调函数中,串口发送采样值数据时,加上了数据帧的帧头(FrameHeader)和帧尾(FrameTerm)。帧头、帧尾各为2字节,实际中可以为任意数字或符号。此例中,将帧头、帧尾声明为0x5353和0x4545。 

4.初始化 

 /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start(&htim3);
  HAL_TIM_Base_Start(&htim8);
  HAL_DAC_Start_DMA(&hdac2,DAC_CHANNEL_1,(uint32_t*)SineWaveDataPh0,DAC_BUFFER_SIZE,DAC_ALIGN_12B_R);
  HAL_DAC_Start_DMA(&hdac1,DAC_CHANNEL_1,(uint32_t*)SineWaveDataPh90,DAC_BUFFER_SIZE,DAC_ALIGN_12B_R);
  HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
  HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1ConvertedData,ADC_CONVERTED_DATA_BUFFER_SIZE);
  HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
  HAL_ADC_Start_DMA(&hadc2,(uint32_t*)&ADC2ConvertedData,ADC_CONVERTED_DATA_BUFFER_SIZE);
/* USER CODE END 2 */

5.变量声明

/* USER CODE BEGIN PV */
/* 带三次谐波的波形数据 */
uint16_t SineWaveDataPh0[DAC_BUFFER_SIZE] = {2047,2147,2246,2344,2441,2536,2629,2718,2805,
		 2888,2968,3043,3113,3179,3240,3296,3347,3393,3433,3467,3497,3521,3540,3554,3563,3567,3567,
		 3564,3556,3545,3530,3514,3494,3473,3450,3427,3402,3377,3352,3328,3304,3282,3261,3241,3224,
		 3209,3196,3186,3179,3175,3173,3175,3179,3186,3196,3209,3224,3241,3261,3282,3304,3328,3352,
		 3377,3402,3427,3450,3473,3494,3514,3530,3545,3556,3564,3567,3567,3563,3554,3540,3521,3497,
		 3467,3433,3393,3347,3296,3240,3179,3113,3043,2968,2888,2805,2718,2629,2536,2441,2344,2246,
		 2147,2048,1948,1849,1751,1654,1559,1466,1377,1290,1207,1127,1052,982,916,855,799,748,702,662,
		 620,598,574,555,541,532,528,528,531,539,550,565,581,601,622,645,668,693,718,743,767,791,813,
		 834,854,871,886,899,909,916,920,922,920,916,909,899,886,871,854,834,813,791,767,743,718,693,
		 668,645,622,601,581,565,550,539,531,528,528,532,541,555,574,598,628,662,702,748,799,855,916,
		 982,1052,1127,1207,1290,1377,1466,1559,1654,1751,1849,1948};
/* 初始相位角为0的正弦波的波形数据 */
uint16_t SineWaveDataPh90[DAC_BUFFER_SIZE] = {2047,2112,2176,2240,2304,2368,2431,2494,2557,2619,2680,
		2741,2801,2860,2919,2977,3034,3090,3144,3198,3251,3302,3352,3401,3449,3495,3540,3583,3625,3665,
		3704,3741,3776,3809,3841,3871,3900,3926,3951,3973,3994,4013,4030,4045,4058,4069,4078,4085,4090,
		4093,4094,4093,4090,4085,4078,4069,4058,4045,4030,4013,3994,3973,3951,3926,3900,3871,3841,3809,
		3776,3741,3704,3665,3625,3583,3540,3495,3449,3401,3352,3302,3251,3198,3144,3090,3034,2977,2919,
		2860,2801,2741,2680,2619,2557,2494,2431,2368,2304,2240,2176,2112,2048,1983,1919,1855,1791,1727,
		1664,1601,1538,1476,1415,1354,1294,1235,1176,1118,1061,1005,951,897,844,793,743,694,646,600,555,
		512,470,430,391,354,319,286,254,224,195,169,144,122,101,82,65,50,37,26,17,10,5,2,0,2,5,10,17,26,
		37,50,65,82,101,122,144,169,195,224,254,286,319,354,391,430,470,512,555,600,646,694,743,793,844,
		897,951,1005,1061,1118,1176,1235,1294,1354,1415,1476,1538,1601,1664,1727,1791,1855,1919,1983};
uint16_t ADC1ConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]={0};
uint16_t ADC2ConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]={0};
uint8_t SignalFlag =0;
uint16_t FrameHeader =0x5353;
uint16_t FrameTerm =0x4545;
/* USER CODE END PV */

        在Simulink接收模型的串口接收(Serial Receive)模块中,也要加上与上述代码中相同的帧头和帧尾。 

6.常量声明

/* USER CODE BEGIN Private defines */
#define DAC_BUFFER_SIZE (uint16_t) 200
#define ADC_CONVERTED_DATA_BUFFER_SIZE (uint16_t) 200
/* USER CODE END Private defines */

四、查看结果

        将DAC2和DAC1的输出(分别为PA6和PA4)分别连接到所配置的ADC1和ADC2的输入通道上(分别为PA0和PA1)。运行Simulink串口接收模型,就会看到Time Scope上显示的波形(按B1键,可以切换通道)。也可以用示波器观察波形。

        把CN8的引脚2与CN8的引脚3用导线连接起来;把CN8的引脚1与把CN5的引脚5用导线连接起来;

1.通过示波器观察到的波形

 

        示波器观察到的2个通道的波形,通道1 显示的是带三次谐波的正弦波形,通道2显示的是正弦波形。

2.通过Time Scope上显示的带谐波的正弦波形

 

 

3.通过Time Scope上显示的正弦波形 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wenchm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值