目录
一、参考工程
二 、硬件配置
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/140815986https://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上显示的正弦波形