天天看点

程序源码分享-STM32将mpu6050的数据DAC并用LCD显示一、DAC配置二、程序分享

本次硬件选用的是正点原子STM32精英版开发板、维特智能的mpu6050(JY62)。通过将JY62读取到的角度数据用lcd显示再DAC并用ADC进行验证。

一、DAC配置

1)开启 PA 口时钟,设置 PA4 为模拟输入。

STM32F103ZET6 的 DAC 通道 1 在 PA4 上,所以,我们先要使能 PORTA 的时钟,然后设置 PA4 为模拟输入。DAC 本是输出,但是为什么端口要设置为模拟输入模式呢?因为一但使能 DACx 通道之后,相应的 GPIO 引脚(PA4 或者 PA5)会自动与 DAC 的模拟输出相连,设置为输入,是为了避免额外的干扰。

使能 GPIOA 时钟:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能 PORTA 时钟

设置 PA1 为模拟输入只需要设置初始化参数即可:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入

2)使能 DAC1 时钟。

同其他外设一样,要想使用,必须先开启相应的时钟。STM32 的 DAC 模块时钟是由 APB1提供的,所以我们调用函数 RCC_APB1PeriphClockCmd()设置 DAC 模块的时钟使能。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能 DAC 通道时钟

3)初始化 DAC,设置 DAC 的工作模式。

该部分设置全部通过 DAC_CR 设置实现,包括:DAC 通道 1 使能、DAC 通道 1 输出缓存关闭、不使用触发、不使用波形发生器等设置。这里 DMA 初始化是通过函数 DAC_Init 完成的:

void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct)

跟前面一样,首先我们来看看参数设置结构体类型 DAC_InitTypeDef 的定义:

typedef struct

{

uint32_t DAC_Trigger;

uint32_t DAC_WaveGeneration;

uint32_t DAC_LFSRUnmask_TriangleAmplitude;

uint32_t DAC_OutputBuffer;

}DAC_InitTypeDef;

这个结构体的定义还是比较简单的,只有四个成员变量。

第一个参数 DAC_Trigger 用来设置是否使用触发功能,前面已经讲解过这个的含义,这里我们不是用触发功能,所以值为DAC_Trigger_None。

第二个参数 DAC_WaveGeneratio 用来设置是否使用波形发生,这里我们前面同样讲解过不使用。所以值为DAC_WaveGeneration_None。

第三个参数 DAC_LFSRUnmask_TriangleAmplitude 用来设置屏蔽/幅值选择器,这个变量只在使用波形发生器的时候才有用,这里我们设置为 0 即可,值为 DAC_LFSRUnmask_Bit0。

第四个参数 DAC_OutputBuffer 是用来设置输出缓存控制位,前面讲解过,我们不使用输出缓存,所以值为 DAC_OutputBuffer_Disable。到此四个参数设置完毕。

5)设置 DAC 的输出值。

通过前面 4 个步骤的设置,DAC 就可以开始工作了,我们使用 12 位右对齐数据格式,所以我们通过设置 DHR12R1,就可以在 DAC 输出引脚(PA4)得到不同的电压值了。

void Dac1_Init(void)
{
  
	GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );	  //使能PORTA通道时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );	  //使能DAC通道时钟 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 		 //模拟输入
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_4)	;//PA.4 输出高
					
	DAC_InitType.DAC_Trigger=DAC_Trigger_None;	//不使用触发功能 TEN1=0
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;	//DAC1输出缓存关闭 BOFF1=1
  DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1

	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
  
  DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值

}
           

二、程序分享

因为程序中ADC用的很简单,而且程序也有很多注释,所以不做过多解释,直接分享给大家一起交流。

硬件接线:
USB-TTL工具                 STM32Core               JY61
VCC          -----           VCC        ----         VCC
TX           -----           RX1(管脚10)     
RX           -----           TX1(管脚9)
GND          -----           GND        ----          GND
                             RX2 (管脚3)       ----  TX
														 TX2 (管脚2)       ----  RX
------------------------------------
 */
#include <string.h>
#include <stdio.h>
#include "Main.h"
#include "UART1.h"
#include "UART2.h"
#include "delay.h"
#include "JY61.h"
#include "DIO.h"
#include "dac.h"  
#include "adc.h"
#include "lcd.h"

struct SAcc 		stcAcc;
struct SGyro 		stcGyro;
struct SAngle 	stcAngle;
//用串口2给JY模块发送指令
void sendcmd(char cmd[])
{
	char i;
	for(i=0;i<3;i++)
		UART2_Put_Char(cmd[i]);
}

//CopeSerialData为串口2中断调用函数,串口每收到一个数据,调用一次这个函数。
void CopeSerial2Data(unsigned char ucData)
{
	static unsigned char ucRxBuffer[250];
	static unsigned char ucRxCnt = 0;	
	LED_REVERSE();					//接收到数据,LED灯闪烁一下
	ucRxBuffer[ucRxCnt++]=ucData;	//将收到的数据存入缓冲区中
	if (ucRxBuffer[0]!=0x55) //数据头不对,则重新开始寻找0x55数据头
	{
		ucRxCnt=0;
		return;
	}
	if (ucRxCnt<11) {return;}//数据不满11个,则返回
	else
	{
		switch(ucRxBuffer[1])//判断数据是哪种数据,然后将其拷贝到对应的结构体中,有些数据包需要通过上位机打开对应的输出后,才能接收到这个数据包的数据
		{
			//memcpy为编译器自带的内存拷贝函数,需引用"string.h",将接收缓冲区的字符拷贝到数据结构体里面,从而实现数据的解析。
			case 0x51:	memcpy(&stcAcc,&ucRxBuffer[2],8);break;
			case 0x52:	memcpy(&stcGyro,&ucRxBuffer[2],8);break;
			case 0x53:	memcpy(&stcAngle,&ucRxBuffer[2],8);break;
		}
		ucRxCnt=0;//清空缓存区
	}
}

void CopeSerial1Data(unsigned char ucData)
{	
	UART2_Put_Char(ucData);//转发串口1收到的数据给串口2(JY模块)
}
//定义
	float ang1,ang2,ang3;
	float vol;	
  u16 adcx;
	float temp;
  u8 x=0;
int main(void)
{ 
	unsigned char i = 0;
	SysTick_init(72,10);//设置时钟频率
	Initial_UART1(9600);//接PC的串口
	Initial_UART2(115200);//接JY61模块的串口	
	
	LED_ON();
	delay_ms(1000);delay_ms(1000);//等等JY61初始化完成

	//功能现象,10秒钟左右会进行一次加速度校准,Z轴角度归零,XYZ角度会缓慢回到0度状态
	while(1)
	{			
		delay_ms(1000);
		i++;
		if(i>9)
		{
			i = 0;
			printf("正在进行加速度校准\r\n");
			sendcmd(ACCCMD);//等待模块内部自动校准好,模块内部会自动计算需要一定的时间
			printf("加速度校准完成\r\n");
			delay_ms(100);
			printf("进行Z轴角度清零\r\n");
			sendcmd(YAWCMD);
			printf("Z轴角度清零完成\r\n");
		}
		printf("-----------------------------------\r\n");
		//输出加速度
		//串口接受到的数据已经拷贝到对应的结构体的变量中了,根据说明书的协议,以加速度为例 stcAcc.a[0]/32768*16就是X轴的加速度,
		printf("Acc:%.3f %.3f %.3f\r\n",(float)stcAcc.a[0]/32768*16,(float)stcAcc.a[1]/32768*16,(float)stcAcc.a[2]/32768*16);
		delay_ms(10);
		//输出角速度
		printf("Gyro:%.3f %.3f %.3f\r\n",(float)stcGyro.w[0]/32768*2000,(float)stcGyro.w[1]/32768*2000,(float)stcGyro.w[2]/32768*2000);
		delay_ms(10);
		//输出角度
		printf("Angle:%.3f %.3f %.3f\r\n",(float)stcAngle.Angle[0]/32768*180,(float)stcAngle.Angle[1]/32768*180,(float)stcAngle.Angle[2]/32768*180);
		delay_ms(10);
		//运算
		ang1=(float)stcAngle.Angle[0]/32768*180;
		ang2=(float)stcAngle.Angle[1]/32768*180;
		ang3=(float)stcAngle.Angle[2]/32768*180;
		printf("Angs:%.3f %.3f %.3f\r\n",ang1,ang2,ang3);
	LCD_Init();			 	 //LCD初始化
	Adc_Init();		  		//ADC初始化
	Dac1_Init();		 	//DAC通道1初始化	
	DAC_SetChannel1Data(DAC_Align_12b_R,0);
  POINT_COLOR=RED;//设置字体为红色 
	LCD_ShowString(60,50,200,16,16,"STM32");	
	LCD_ShowString(60,70,200,16,16,"DAC TEST");	
	LCD_ShowString(60,90,200,16,16,"2021/7/30");		
	//显示提示信息											      
	POINT_COLOR=BLUE;//设置字体为蓝色
	LCD_ShowString(60,110,200,16,16,"DAC VAL:");	      
	LCD_ShowString(60,130,200,16,16,"DAC VOL:0.000V");	      
	LCD_ShowString(60,150,200,16,16,"ADC VOL:0.000V");
	LCD_ShowString(60,170,200,16,16,"Angx:");	      
	LCD_ShowString(60,190,200,16,16,"Angy:");	      
	LCD_ShowString(60,210,200,16,16,"Angz:");
	LCD_ShowxNum(100,170,ang1,4,16,0);
	LCD_ShowxNum(100,190,ang2,4,16,0);
	LCD_ShowxNum(100,210,ang3,4,16,0);
	//DAC部分	
 		  DAC_SetChannel1Data(DAC_Align_12b_R,ang1); 
		  adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
			LCD_ShowxNum(124,110,adcx,4,16,0);     	//显示DAC寄存器值
			temp=(float)adcx*(3.3/4096);			//得到DAC电压值
			adcx=temp;
 			LCD_ShowxNum(124,130,temp,1,16,0);     	//显示电压值整数部分
 			temp-=adcx;
			temp*=1000;
			LCD_ShowxNum(140,130,temp,3,16,0X80); 	//显示电压值的小数部分
 			adcx=Get_Adc_Average(ADC_Channel_1,10);		//得到ADC转换值	  
			temp=(float)adcx*(3.3/4096);			//得到ADC电压值
			adcx=temp;
 			LCD_ShowxNum(124,150,temp,1,16,0);     	//显示电压值整数部分
 			temp-=adcx;
			temp*=1000;
			LCD_ShowxNum(140,150,temp,3,16,0X80); 	//显示电压值的小数部分		 
		  delay_ms(10);	
	
  }
		
}//主循环





           

继续阅读