查看: 9859  |  回复: 10
参赛作品《便携式多功能数字示波器》

主题

回复
发表于2017-06-02 10:42:03 | 显示全部楼层
1# 电梯直达

1. 参赛者姓名(必填项):盖照东

 2. 单位或学校名称(必填项):山东科技大学

3. 当前职务或职称(必填项):学生

4. 参赛作品的名字(必填项):便携式多功能数字示波器

5. 简要陈述您的idea和作品(必填项):使用stm32内置AD转换功能将测得的模拟信号转换为数字信号,并送给单片机,单片机处理后,在显示屏上显示所测波形,在触摸屏上进行人机交互,可设定不同的工作模式,使用stm32内置DA转换功能输出标准三角波,正弦波,矩形波,方便检测示波器是否正常,或用于其他用途

6. 拟用到的立创商城在售物料(必填项):stm32f103zet6,TL084,L7805,L7905,CD4051,各种电容,电阻,5v继电器,MC34063,ULN2003等等

7. 拟用到的非立创商城物料或其它补充(必填项):4.63寸触摸液晶屏

 

【作品正式发表(报名成功后进入设计阶段)需要填写的内容】


一、作品简介

1.作品的整机外观图片或焊接组装好的PCBA图片;

这次准备不充分,画好PCB板的时候就剩3天了

PCB打样已经来不及,还好有两块覆铜板,只能腐蚀电路板了,技术有限,焊的有点难看,请见谅 

 

  

 

 点击查看大图   

 点击查看大图 

 点击查看大图    

 

方波输出

 

 

 

 

 三角波输出

 

 

 正弦波输出

 

 

上位机

  

 

 

2.作品在创新性、趣味性、实用性甚至公益性方面,有哪些亮点可体现

主控:                                        STM32F103ZET6
液晶屏:                                      4.63TFT480×272  彩色LCD显示屏, ILI9325控制器, FSMC驱动
触摸屏:                                  电阻触摸屏 HR2046控制器
AD:                                          使用stm32内部ADC,121MHz采样率
最高实时取样率:                   1MSa/s  12Bits
取样缓冲器深度:                   5K  
垂直灵敏度:                            5V1V500mV,200mV,100mV,50mV,20mV,10mV;  
水平时基范围:2S,1S,500mS,200mS,100mS,50mS,20mS,10mS,5mS,2mS,1mS,500uS,200uS,100uS,50uS,20uS,10uS,5uS,2uS,1uS
输入阻抗:                                 1MΩ
最高输入电压:                       30Vpp
耦合方式:                                 AC/DC
触发功能:                                 实现自动、常规、单次触发方式 ,上升或下降边沿触发  
参数计算:                                 频率、周期、占空比、交流峰-峰值、平均值、光标追踪显示
图形接口:  UCGUI 3.90
操作系统: uC/OS-II


功能:
1、波形发生器:使用STM32一路DA实现正弦,三角波,方波,白噪声输出。 任意一种波形幅值在0-3.3V任意可调、频率在一定范围任意可调、方波占空比可调。调节选项可以通过触摸屏完成设置。
2SD卡存储: SD卡波形存储输出,能够对当前屏幕截屏,以JPG格式存储在SD卡上。能够存储1S内的波形数据,可以随时调用查看。
31)实现STOP/RUN功能(2)输出波形电压、时间参数(3)控制截屏(4)控制波形发生器(5)控制完成FFT6)波形的存储和显示
2、水平扫速:  250 ns*500ns1μs5 μs10μs50μs500 μs5ms 50ms
3、垂直电压灵敏度:10mV/div, 20mV/div, 50mV/div, 0.1V/div, 0,2V/div, 0.5V/div, 1V/div,
2V/div, 5V/div
4、被测信号的各种参数屏幕显示,包括频率、电压峰峰值等。
 
人机界面还有待优化, SD卡存储功能实现的不太好,经常会死机,时间有点紧迫,所以关于SD卡的那段代码先放一放,集中精力做示波器前端电路板
 
 
二、系统构架图
  
 
 
 
 
三、硬件部分的描述
 
   
 
硬件电路主要分为耦合电路(DC/AC),衰减电路,平移电路,增益调节电路。
耦合电路用于区分输入信号是交流还是直流,   平移电路使用OP07运放将输入信号电压转换为AD可识别的电压,增益调节电路由STM32控制模拟开关CD4051,从而调节反馈电阻,来调节增益的大小。
 
 
 

四、材料清单(BOM列表)

列出您这个作品所用到的主要器件(关键器件即可),比如单片机&ARM芯片、专用集成芯片(ASIC)、传感器、功能模块等。

如果所列出的芯片是来自我们立创商城上的,最好能写出该器件的商品编号或附上对应购买链接。

继电器 http://www.szlcsc.com/product/details_36422.html
ULN2003 http://www.szlcsc.com/product/details_108437.html
CD4051 http://www.szlcsc.com/product/details_136203.html
TL084 http://www.szlcsc.com/product/details_11677.html
OP07 http://www.szlcsc.com/product/details_90892.html
LM311 http://www.szlcsc.com/product/details_100595.html
STM32F13ZET6 http://www.szlcsc.com/product/details_8779.html

五、软件部分的描述(选填)

 

1. 配置ADC1完成AD采集,是本示波器最核心的部分
ADC1由TIM3提供的触发事件进行触发AD转换,控制TIM3的速率就可以完成采样速率的改变,同时采用DMA完成数据传输,注入通道1。
配置TIM3工作在18MHz,为AD提供触发
  DMA把AD值传输到缓冲区完成后关闭定时器3,同时置更新完成标志位为1,开定时器3在应用中开启。


2.STM32内部自带两个12位DAC,电压输出型,启用其中的DAC1通道输出电压,转换范围从0~Vref,定义三个波形表,采用查表法,结合DMA产生正弦波,三角波,矩形波,使用TIM2作为触发更新源触发DAC1产生各种波形/
  频率计算公式:Feq=72MHz/(TIM_Prescaler+1)/TIM_Period/波形点数

3. 示波器主任务完成了获取频率周期等时间参量和电参量并完成计算,是核心任务,优先级最高。加入了上位机程序,产生了上位机与下位机进行通信的问题,自定义了通信协议,每一帧长度16Byte,由命令帧和数据帧组成,帧头和帧尾作为校验码,限于目前水平,采用了较为简单的ASCII编码协议技术,同时为了快速响应上位机命令,把解码模块放在ISR中完成,响应速度小于1.5ms。经计算,自定义的通信协议有效传输速率理论最大可达16000bps,实际采用10666bps。

4.示波器配合上位机使用,可用上位机进行增益控制,时基控制,信号发生器控制,扫频和信号分析。STM32将采集到的数据发送给上位机,上位机根据需求可进行傅里叶变换,频谱分析,功率谱分析等等,然后将分析过的数据送到STM32,通过液晶屏显示。这样既降低了STM32的负担,同时又拥有更强大的功能。

 函数说明:配置ADC1完成AD采集,是本示波器最核心的部分.
 配置方案:ADC1由TIM3提供的触发事件进行触发AD转换,控
 		  制TIM3的速率就可以完成采样率的改变.同时采
		  用DMA完成数据传输,注入通道1完成内部温度传
		  感器AD采集. 
--------------------------------------------------*/
void ADC1_Mode_Config(void)
{
	//配置DMA
	DMA_InitTypeDef DMA_csh;
	ADC_InitTypeDef ADC_csh;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	DMA_DeInit(DMA1_Channel1);  					   //DMA复位,通道1
	DMA_csh.DMA_PeripheralBaseAddr = ADC1_DR_Address;  //ADC1地址
	DMA_csh.DMA_MemoryBaseAddr = (unsigned int)ADCConvertedValue;  //内存地址
	DMA_csh.DMA_DIR = DMA_DIR_PeripheralSRC;  
	DMA_csh.DMA_BufferSize = SAMPDEPTH;  			  		//缓冲大小为采样深度
	DMA_csh.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址固定
	DMA_csh.DMA_MemoryInc = DMA_MemoryInc_Enable; 			//内存地址自增
	DMA_csh.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  
	DMA_csh.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_csh.DMA_Mode = DMA_Mode_Circular;  					//循环传输
	DMA_csh.DMA_Priority = DMA_Priority_High;  				//DMA优先级高
	DMA_csh.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1,&DMA_csh);  						//写入DMA1配置参数
	DMA_Cmd(DMA1_Channel1,ENABLE);	   						//使能DMA1通道1
	DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);			//使能DMA CH1中断

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	//配置TIM3工作在18MHz,为AD提供触发
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
	TIM_TimeBaseStructure.TIM_Period = 1;          
	TIM_TimeBaseStructure.TIM_Prescaler = 99; 	//工作在18M,每格最大值时,不至于溢出      
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;    
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
	TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //使用TIM3事件更新作为ADC触发
	
	//配置ADC
	ADC_csh.ADC_Mode = ADC_Mode_Independent;  		//独立ADC模式
    ADC_csh.ADC_ScanConvMode = DISABLE;   			//关闭扫描模式
	ADC_csh.ADC_ContinuousConvMode = DISABLE;  		//连续AD转换开启
	ADC_csh.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;  //由TIM3提供的触发事件进行触发AD转换
	ADC_csh.ADC_DataAlign = ADC_DataAlign_Right; 	//数据右对齐
	ADC_csh.ADC_NbrOfChannel = 1;  					//要转换的通道数目1
	ADC_Init(ADC1,&ADC_csh);   						//写入ADC1配置参数
	ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_1Cycles5);//采样速率1M
	ADC_DMACmd(ADC1,ENABLE); 						//使能ADC1 DMA
	ADC_ExternalTrigConvCmd(ADC1,ENABLE);			//打开ADC1外部触发
	
	ADC_InjectedChannelConfig(ADC1,ADC_Channel_16,1,ADC_SampleTime_239Cycles5);	 //配置ADC1通道16为注入通道1
	ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_None);	 //软件触发注入通道的转换
	ADC_TempSensorVrefintCmd(ENABLE);											 //使能温度传感器

	ADC_Cmd(ADC1,ENABLE); 							//使能ADC1
	ADC_ResetCalibration(ADC1);	  					//复位校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC1));     //等待校准寄存器复位完成
	ADC_StartCalibration(ADC1);	  					//开始校准
	while(ADC_GetCalibrationStatus(ADC1)); 			//等待校准完成
	TIM_Cmd(TIM3,ENABLE);
}
/*-----------------------------------------
 函数说明:通过注入通道1转换内部温度传感器
 		  AD值,读取10次有效数据取平均返回 
------------------------------------------*/
u16 GetTempSensor(void)   
{ 
	u16 temp=0,i,k=0;
	for(i=0; i<10; )
	{
		ADC_SoftwareStartInjectedConvCmd(ADC1,ENABLE);	//软件触发注入通道的转换
		k = (0x6EE - ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1)) / 0x05 + 25;
		if(k>0 && k<100)
		{
			temp += k;
			i++;
		}
	}
	temp /= 10;
	return temp;	     
}
/*-----------------------------------------
 函数说明:ADC1初始化 
------------------------------------------*/
void ADC1_Init(void)
{
	ADC1_GPIO_Init();
	ADC1_Mode_Config();
}
/*-----------------------------------------
 函数说明:ADC传输DMA通道1中断服务程序
 		  DMA把AD值传输到缓冲区完成后关闭定
		  时器3(作为触发AD转换的定时器)同时
		  置更新完成标志位为1,开定时器3在应
		  用中开启. 
------------------------------------------*/
void DMA1_Channel1_IRQHandler()
{
      OSIntNesting++;  
      DMA_ClearFlag(DMA1_FLAG_TC1);	//清除DMA传输完成中断
      TIM_Cmd(TIM3,DISABLE);		//关闭TIM3
      WaveCtrl.UpdatTrue = 1;		//已经完成一次波形FIFO,可以批量读出数据
      OSIntExit();
}
/*-----------------------------------------
 函数说明:擦除AD缓冲区 
------------------------------------------*/
void Earse_AD_FIFO(void)
{
	uint32_t i;
 	for(i=0; i<SAMPDEPTH; i++)
	{
		ADCConvertedValue[i] = 0;
	}	
}
/*------------------------------------------------------------------------------------------
		    				STM32 DAC配置驱动程序(v2.0)
 
 说明:   使用TIM2作为触发更新源触发DAC1产生三角波.

	      用查表法结合DMA产生正弦波,三角波,矩形波等等,功能更加
	      强大好用,使用了DMA2通道3,和DAC1。
		  频率计算公式:
		  Feq=72MHz/(TIM_Prescaler+1)/TIM_Period/波形点数
-----------------------------------------------------------------------------------------*/
#include "dac.h"
#include "stm32f10x.h"
/*--------------------------
 	  1个周期32点波形表
--------------------------*/
uc16 SineWaveTab[32] = {2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
                      	3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 
                      	599 , 344 , 155 , 38,0, 38, 155, 344, 599, 909, 1263, 1647};

uc16 TriangleWaveTab[32] = {0,255,511,767,1023,1279,1535,1791,2047,2303,2559,2815,3071,3327,3583,3839,4095,
							3839,3583,3327,3071,2815,2559,2303,2047,1791,1535,1279,1023,767,511,255};

uc16 SawtoothWaveTab[32] = {127,255,383,511,639,767,895,1023,1151,1279,1407,1535,1663,1791,1919,2047,2175,
							2303,2431,2559,2687,2815,2943,3071,3199,3327,3455,3583,3711,3839,3967,4095};

u16  AnyWaveTab[32] = {0};	  //存储任意的波形数据
/*-------------------------------------
 函数功能: DAC参数配置,默认产生正弦波
 函数参数: 无
 返 回 值: 无
-------------------------------------*/
void DAC_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef  DAC_InitStructure;
	DMA_InitTypeDef  DMA_InitStructure;

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);
	//DAC1->PA4   DAC2->PA5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//设置为模拟输入
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	GPIO_SetBits(GPIOA,GPIO_Pin_4);   //PA4 = 1
		
	DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_Init(DAC_Channel_1, &DAC_InitStructure);
	
	DACTriggerByTIM2(800,0);		  //2812Hz正弦波
	
	DMA_DeInit(DMA2_Channel3);
	DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40007408; //DAC_DHR12R1_Address
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SineWaveTab;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = 32;				   //波形点数32
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA2_Channel3, &DMA_InitStructure);
	
	DMA_Cmd(DMA2_Channel3, ENABLE);	
	DAC_Cmd(DAC_Channel_1, ENABLE);	
	DAC_DMACmd(DAC_Channel_1, ENABLE);	
}
/*--------------------------
 函数功能: DAC输出直流电压设置
 函数参数: 电压值vol
 返 回 值: 无
--------------------------*/
void Set_DAC_Value(unsigned int vol)	//vod:0~3300 = 0~3.3V
{
	float temp;
	temp = vol;
	temp /= 1000;
	temp = temp*(4095/3.3);
	DAC_SetChannel1Data(DAC_Align_12b_R,temp);
}
/*-----------------------------------------------
函数功能: TIM2定时器配置模块
函数参数: ARR寄存器值0-65535,预分频值0-65535
调用示例: DACTriggerByTIM2(1,1);
-----------------------------------------------*/
void DACTriggerByTIM2(unsigned short int Auto_Reload,unsigned short int Clock_Div)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

	TIM_TimeBaseStructure.TIM_Prescaler =  Clock_Div; 			//时钟预分频
	TIM_TimeBaseStructure.TIM_CounterMode =  TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseStructure.TIM_Period = Auto_Reload;				//自动重装值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;	    //时钟分频1
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
	TIM_SelectOutputTrigger(TIM2,TIM_TRGOSource_Update);       //使用TIM2事件更新作为DAC触发
	TIM_Cmd(TIM2,ENABLE);    //打开TIM2
}

 

/*-------------------------------------------------------------------------------------------
 			                   STM32示波器GUI任务
 
 说明: 示波器需要良好的人机界面交互才具备可操作性,本GUI任务完成液晶屏和触摸屏的人机界面交互
	   采用了uCGUI-MEMDEV技术来完成波形显示窗口无闪烁绘制图形,其余GUI均为自写的GUI.
	   包括追踪线的计算,显示;无闪烁绘制波形算法,显示参数面板,显示交互菜单,检测事件发生等等
	   最核心的函数为处理AD缓冲区的数据,完成了寻找最大值最小值等等电参量的计算.浮点运算较多.
	   为保证对共享资源的有效和安全利用,采用了互斥信号量进行操作,保证共享资源安全.
		    追踪线宏定义
------------------------------------------*/
#define TRACKLINE_BOTH_CLOSE 	(0)
#define TRACKLINE_VPP_OPEN   	(1)
#define TRACKLINE_PRIOD_OPEN 	(2)
#define TRACKLINE_BOTH_OPEN  	(3)

#define PRAMPANEL_BOTH_CLOSE 	(0)
#define PRAMPANEL_TIME_OPEN   	(1)
#define PRAMPANEL_VOLT_OPEN 	(2)
#define PRAMPANEL_BOTH_OPEN  	(3)

/*------------------------------------------
		    	声明变量
------------------------------------------*/
extern  OS_EVENT *LCD_Buffer_MUTEX;
extern  OS_EVENT *USART_Buffer_MUTEX;
extern  OS_EVENT *SDtoRAM_Buffer_MUTEX;

extern  u8  LCD_Buffer[LCD_BUFFER_SIZE];
extern  u8  USART_Buffer[USART_BUFFER_SIZE];
extern  u16 ADCConvertedValue[SAMPDEPTH];

extern  WaveType    WaveInfo;			  //波形参数
extern  WaveMode    WaveCtrl;			  //控制参数
extern  FG_WaveType FG_WaveInfo;	      //信号发生器参数

INT16S  ADCVlaue2ScreenValue[SAMPDEPTH];  //显示波形缓冲区,占用RAM 0.78KB

u8      TrackLine_VppMax,				  //追踪线全局变量
		TrackLine_VppMin;

u16		TrackLine_PriodStart,
		TrackLine_PriodEnd;
										  
u8      TrackLine_Switch = TRACKLINE_BOTH_CLOSE; //追踪线开关
u8      PramPanel_Switch = PRAMPANEL_BOTH_CLOSE; //参数面板开关

u16 	Tpx=0,Tpy=0,ZBX=0,ZBY=0;		  //触摸屏AD值,坐标值

/*----------------------------------------------------------------
 函数功能: GUI_DrawGraph(I16 *paY, int NumPoints, int x0, int y0);
 函数参数: paY - 纵坐标的数组头指针
   		   NumPoints - 所需绘制的图象的点数
		   x0,y0 - 坐标原点在TFT_LCD屏幕上的坐标
 返 回 值: 无
-----------------------------------------------------------------*/
void Draw(void *p) 
{
	int i;
	(void)p;
	GUI_SetBkColor(GUI_BLACK);
	GUI_SetColor(GUI_LIGHTBLUE);
	GUI_SetFont(&GUI_Font6x8);
	GUI_SetTextMode(GUI_TM_TRANS); 			 //透明文本模式
	GUI_ClearRect(0,0,SAMPDEPTH,200);
	GUI_DrawRect (0,0,SAMPDEPTH-1,200);	  
	
	//画水平刻度线
	for (i = 0; i < 200; i += 20) 
	{
		GUI_DrawHLine(20 + i,1,SAMPDEPTH-1);  //(Y轴坐标,起点X坐标,终点X坐标)
	}
	GUI_DrawHLine(101,1,SAMPDEPTH-1);
	GUI_DrawHLine(99,1,SAMPDEPTH-1);
	//画垂直刻度线
	for (i = 40; i <= SAMPDEPTH; i += 40) 
	{
		GUI_DrawVLine(0 + i,1,200);
	}
	GUI_DrawVLine(199,1,200);
	GUI_DrawVLine(201,1,200);
	//画标度尺
	for (i = 10; i < 200;i += 20)GUI_DrawHLine(i,195,205);
	for (i = 20; i < 400;i += 40)GUI_DrawVLine(i,95,105);
	//画追踪线
	if(TrackLine_Switch != TRACKLINE_BOTH_CLOSE)
	{   
		GUI_SetColor(GUI_GREEN);
		switch(TrackLine_Switch)
		{
		 	case TRACKLINE_VPP_OPEN:
				 GUI_DrawHLine(TrackLine_VppMax+4,1,SAMPDEPTH-2);
				 GUI_DrawHLine(TrackLine_VppMin,1,SAMPDEPTH-2);
				 GUI_DispDecAt(TrackLine_VppMax,2,TrackLine_VppMax+6,3);
				 GUI_DispDecAt(TrackLine_VppMin,2,TrackLine_VppMin-8,3);
				 break;
			
			case TRACKLINE_PRIOD_OPEN:	
				 GUI_DrawVLine(TrackLine_PriodStart-2,1,187);
				 GUI_DrawVLine(TrackLine_PriodEnd+2,1,187);
				 GUI_DispDecAt(TrackLine_PriodEnd,TrackLine_PriodEnd-6,190,3);
				 GUI_DispDecAt(TrackLine_PriodStart,TrackLine_PriodStart-9,190,3);
				 break;

			case TRACKLINE_BOTH_OPEN:
				 GUI_DrawHLine(TrackLine_VppMax+4,1,SAMPDEPTH-2);
				 GUI_DrawHLine(TrackLine_VppMin,1,SAMPDEPTH-2);
				 GUI_DispDecAt(TrackLine_VppMax,2,TrackLine_VppMax+6,3);
				 GUI_DispDecAt(TrackLine_VppMin,2,TrackLine_VppMin-8,3);
				 
				 GUI_DrawVLine(TrackLine_PriodStart-2,1,187);
				 GUI_DrawVLine(TrackLine_PriodEnd+2,1,187);
				 GUI_DispDecAt(TrackLine_PriodEnd,TrackLine_PriodEnd-6,190,3);
				 GUI_DispDecAt(TrackLine_PriodStart,TrackLine_PriodStart-9,190,3);
			     break;
			default:break;	
		}
	}

	GUI_SetColor(GUI_YELLOW);
	GUI_DrawGraph(ADCVlaue2ScreenValue,SAMPDEPTH,0,0);//往GUI中绘波形图
//	GUI_DispDecAt(ZBX,370,25,3);
//	GUI_DispDecAt(ZBY,370,45,3);
	
	if(PramPanel_Switch != PRAMPANEL_BOTH_CLOSE)
	{		
		switch(PramPanel_Switch)
		{
			case PRAMPANEL_VOLT_OPEN:
				 GUI_DispStringAt("Vmax = ",320,120);GUI_DispFloat(WaveInfo.Vmax,5);
				 GUI_DispStringAt("Vmin = ",320,130);GUI_DispFloat(WaveInfo.Vmin,5);
				 GUI_DispStringAt("Vpp  = ",320,140);GUI_DispFloat(WaveInfo.Vpp,5);
				 GUI_DispStringAt("Vrms = ",320,150);GUI_DispFloat(WaveInfo.Vrms,5);
				 break;

			case PRAMPANEL_TIME_OPEN:
				 GUI_DispStringAt("Priod= ",220,120);GUI_DispDecMin(WaveInfo.Priod);GUI_DispString("uS");
				 GUI_DispStringAt("Freq = ",220,130);GUI_DispDecMin(WaveInfo.Frequency);GUI_DispString("Hz");
				 GUI_DispStringAt("High = ",220,140);GUI_DispDecMin(WaveInfo.HighWidth);GUI_DispString("uS");
				 GUI_DispStringAt("Lows = ",220,150);GUI_DispDecMin(WaveInfo.LowWidth);GUI_DispString("uS");
				 GUI_DispStringAt("Duty = ",220,160);GUI_DispDecMin(WaveInfo.DutyCycle);GUI_DispString("%");
				 break;

			case PRAMPANEL_BOTH_OPEN:
				 GUI_DispStringAt("Vmax = ",320,120);GUI_DispFloat(WaveInfo.Vmax,5);
				 GUI_DispStringAt("Vmin = ",320,130);GUI_DispFloat(WaveInfo.Vmin,5);
				 GUI_DispStringAt("Vpp  = ",320,140);GUI_DispFloat(WaveInfo.Vpp,5);
				 GUI_DispStringAt("Vrms = ",320,150);GUI_DispFloat(WaveInfo.Vrms,5);
				 GUI_DispStringAt("Priod= ",220,120);GUI_DispDecMin(WaveInfo.Priod);GUI_DispString("uS");
				 GUI_DispStringAt("Freq = ",220,130);GUI_DispDecMin(WaveInfo.Frequency);GUI_DispString("Hz");
				 GUI_DispStringAt("High = ",220,140);GUI_DispDecMin(WaveInfo.HighWidth);GUI_DispString("uS");
				 GUI_DispStringAt("Lows = ",220,150);GUI_DispDecMin(WaveInfo.LowWidth);GUI_DispString("uS");
				 GUI_DispStringAt("Duty = ",220,160);GUI_DispDecMin(WaveInfo.DutyCycle);GUI_DispString("%");
				 break;

			default:break;
		}
	}
}
/*-----------------------------------------
 函数功能:在LCD上显示波形关键参数
 函数说明:注意本函数多次操作共享资源,使用了
		  互斥信号量作为安全保证
------------------------------------------*/
void DisplayWaveInfo(void)
{
	uint8_t err;
 	//完成电压参数显示
	OSMutexPend(LCD_Buffer_MUTEX,0,&err);	   //占用信号量		
	sprintf(LCD_Buffer,"Vmax:%1.2fV  Vmin:%1.2fV  Vpp:%2.2fV  Vrms:%2.2fV",WaveInfo.Vmax,
												       			   		   WaveInfo.Vmin,
												       			   		   WaveInfo.Vpp,
																   		   WaveInfo.Vrms);
	virtual_LCM_PutString(10,210,LCD_Buffer,Green,Black,1);	
	OSMutexPost(LCD_Buffer_MUTEX);			   //释放信号量

	OSMutexPend(LCD_Buffer_MUTEX,0,&err);	   //占用信号量
	sprintf(LCD_Buffer,"T:%5duS   F:%5dHz ",WaveInfo.Priod,WaveInfo.Frequency);
	virtual_LCM_PutString(10,230,LCD_Buffer,Green,Black,1);
	OSMutexPost(LCD_Buffer_MUTEX);			   //释放信号量

	OSMutexPend(LCD_Buffer_MUTEX,0,&err);	   //占用信号量
	sprintf(LCD_Buffer,"H:%5duS   L:%5duS    Duty:%2d ",WaveInfo.HighWidth,
												        WaveInfo.LowWidth,
												        WaveInfo.DutyCycle);
	virtual_LCM_PutString(10,250,LCD_Buffer,Green,Black,1);
	OSMutexPost(LCD_Buffer_MUTEX);			   //释放信号量

//	OSMutexPend(LCD_Buffer_MUTEX,0,&err);	   //占用信号量
//	sprintf(LCD_Buffer,"AMP:%.2f",WaveCtrl.AmpDiv);												      
//	LCD_Write_String(210,225,LCD_Buffer,Green,Black);
//	OSMutexPost(LCD_Buffer_MUTEX);			   //释放信号量
	
	OSMutexPend(LCD_Buffer_MUTEX,0,&err);	   //占用信号量
	sprintf(LCD_Buffer,"TMP:%d ",GetTempSensor());												      
	virtual_LCM_PutString(210,230,LCD_Buffer,Green,Black,1);
	OSMutexPost(LCD_Buffer_MUTEX);			   //释放信号量
}
/*-----------------------------------------
 函数说明:在LCD上显示实时波形
------------------------------------------*/
void ShowRealTimeWave(void)
{
	GUI_RECT Rect = {0,0,479,200};					 //无闪烁显示区域
	int i,j=0;
	OS_CPU_SR  cpu_sr = 0u;
	WaveInfo.Vmax = 2047.0;
	WaveInfo.Vmin = 2047.0;

	for (i = 0; i < SAMPDEPTH; i++) 
	{	//把AD值按比例转换成在LCD上显示的值
		ADCVlaue2ScreenValue[i] = ( ADCConvertedValue[i]*200/4096 );  
			
		if(WaveInfo.Vmax < ADCConvertedValue[i])	 //找出Vmax Vmin
		{
			WaveInfo.Vmax = ADCConvertedValue[i];	
		}
		if(WaveInfo.Vmin > ADCConvertedValue[i])
		{
		 	WaveInfo.Vmin = ADCConvertedValue[i];	
		}
		//周期追踪线寻找
		if(ADCVlaue2ScreenValue[i]>98 && ADCVlaue2ScreenValue[i]<102 && j==0 && i>10 && i<200)
		{
			if(ADCVlaue2ScreenValue[i-5]>101 && ADCVlaue2ScreenValue[i+5]<99)
			{
		 		TrackLine_PriodStart = i;
				j = 1;
			}
		}
		else if(ADCVlaue2ScreenValue[i]>98 && ADCVlaue2ScreenValue[i]<102 && j==1 && i>TrackLine_PriodStart+20 && i<SAMPDEPTH)
		{
			if(ADCVlaue2ScreenValue[i-5]>101 && ADCVlaue2ScreenValue[i+5]<99)
			{
		 		TrackLine_PriodEnd = i;
				j = 2;
			}
		}
	}
	
	TrackLine_VppMax = 200 - WaveInfo.Vmax*200/4096;	 //最大值追踪线
	TrackLine_VppMin = 200 - WaveInfo.Vmin*200/4096;	 //最小值追踪线
	
	if(JDQ_ACDC == 1)   //AC耦合
	{
	 	WaveInfo.Vmax -= 2047.0;
		WaveInfo.Vmin -= 2047.0;	
	}
	WaveInfo.Vmax = (WaveInfo.Vmax/4095 * 3.3 * WaveCtrl.AmpDiv);
	WaveInfo.Vmin = (WaveInfo.Vmin/4095 * 3.3 * WaveCtrl.AmpDiv);
	WaveInfo.Vpp  = WaveInfo.Vmax - WaveInfo.Vmin;	
	WaveInfo.Vrms = WaveInfo.Vpp*1000 / 2828;	
	
	OS_ENTER_CRITICAL();
	GUI_MEMDEV_Draw(&Rect,&Draw,ADCVlaue2ScreenValue,0,0); //GUI无闪烁绘制波形
	OS_EXIT_CRITICAL();	
}

/*-----------------------------------------
 函数说明:在LCD上显示存储的波形
------------------------------------------*/
void ShowSavedWave(void)
{
	uint16_t i;
//	SD_LoadWaveADValue();		  //从SD卡载入波形
	WaveCtrl.ReadSD = 0;
	WaveInfo.Vmax = 2047.0;
	WaveInfo.Vmin = 2047.0;
	virtual_LCM_Rectangle_V2(2,2,478,200,Black,1);//指定位置清屏
	for(i=3; i<SAMPDEPTH-2; i++)
	{	
		Draw_Line(i-1,(uint16_t)((ADCConvertedValue[i-1]*200/4096)),
				  i,  (uint16_t)((ADCConvertedValue[i]*200/4096)),Blue2);
		Draw_Line(i-1,(uint16_t)((ADCConvertedValue[i-1]*200/4096)+1),
				  i,  (uint16_t)((ADCConvertedValue[i]*200/4096)+1),Blue2);		
		if(WaveInfo.Vmax < (float)ADCConvertedValue[i])
		{
			WaveInfo.Vmax =(float)ADCConvertedValue[i];	
		}
		if(WaveInfo.Vmin > (float)ADCConvertedValue[i])
		{
		 	WaveInfo.Vmin =(float)ADCConvertedValue[i];	
		}
	}	 
	
	if(JDQ_ACDC == 1)   //AC耦合
	{
	 	WaveInfo.Vmax -= 2047.0;
		WaveInfo.Vmin -= 2047.0;	
	}
	WaveInfo.Vmax = (float)(WaveInfo.Vmax/4095 * 3.3 * WaveCtrl.AmpDiv);
	WaveInfo.Vmin = (float)(WaveInfo.Vmin/4095 * 3.3 * WaveCtrl.AmpDiv);
	WaveInfo.Vpp = WaveInfo.Vmax - WaveInfo.Vmin;	
	WaveInfo.Vrms = WaveInfo.Vpp*1000 / 2828;	
}

void ShowWelcomeScreen(void)
{
	Draw_Rectangle(132,70,132*2,90*2,Blue2);
	Draw_Rectangle(131,69,132*2-1,90*2-1,Blue2);		
	virtual_LCM_PutString(132+4,70+6," ARM  Cortex-M3",Yellow,Black,1);
	virtual_LCM_PutString(132+11,70+36,"    Digital",Yellow,Black,1);
	virtual_LCM_PutString(132+13,70+64," Oscilloscope",Yellow,Black,1);
	virtual_LCM_PutString(132+13,70+84,"GZD 2017-08-07",Yellow,Black,1);
}
/*-----------------------------------------
 函数说明:在LCD上显示控制面板
------------------------------------------*/
void DrawControlPanel(void)
{
 	GUI_DrawRect(403,1,477,20);		 //侧边菜单
	GUI_DrawRect(404,2,476,19);

	GUI_DrawRect(1,202,400,270);	 //参数栏
	GUI_DrawRect(2,203,399,269);
	
	GUI_SetFont(&GUI_Font8x16);
	GUI_DispStringHCenterAt("GZD",440,3);
	
	GUI_DrawRect(403,23,477,63);	 //STOP,RUN
	GUI_DrawRect(404,24,476,62);
	GUI_DrawVLine(440,23,63);
	GUI_DrawVLine(441,23,63);
	GUI_DispStringAt("STOP",407,38);
	GUI_DispStringAt("RUN",447,38);
	
	
	GUI_DrawRect(403,65,477,105);	 //AC,DC 
	GUI_DrawRect(404,66,476,104);
	GUI_DrawVLine(440,65,105);
	GUI_DrawVLine(441,65,105);
	GUI_DispStringAt("AC",415,78);
	GUI_DispStringAt("DC",450,78);

	GUI_DrawRect(403,108,477,148);	  //X+ X-
	GUI_DrawRect(404,109,476,147);
	GUI_DrawVLine(440,108,148);
	GUI_DrawVLine(441,108,148);
	GUI_DispStringAt("X+",415,121);
	GUI_DispStringAt("X-",450,121);

	GUI_DrawRect(403,150,477,190);	  //Y+ Y-
	GUI_DrawRect(404,151,476,189);
	GUI_DrawVLine(440,150,190);
	GUI_DrawVLine(441,150,190);
	GUI_DispStringAt("Y+",415,163);
	GUI_DispStringAt("Y-",450,163);

	GUI_DrawRect(403,192,477,230);	  //FG
	GUI_DrawRect(404,193,476,229);
	GUI_DrawVLine(440,192,230);
	GUI_DrawVLine(441,192,230);
	GUI_DispStringAt("SIN",410,205);
	GUI_DispStringAt("SQU",447,205);

	GUI_DrawRect(403,232,477,271);	  //FG
	GUI_DrawRect(404,231,476,270);
	GUI_DrawVLine(440,232,271);
	GUI_DrawVLine(441,232,271);
	GUI_DispStringAt("AUTO",407,245);
	GUI_DispStringAt("TRG",447,245);
}
/*-----------------------------------------
 函数说明:在LCD上显示参数面板
------------------------------------------*/
void DrawPramPanel(void)
{

}
/*-----------------------------------------
 函数说明:触摸事件检测,根据触摸坐标检测哪个
 		  被按下,判断值由实验法测定
------------------------------------------*/
void TouchEventDetected(void)
{
	if(ZBX>100 && ZBX<130 && ZBY>220 && ZBY<250)  //STOP 421 440 58 86 
	{
		Draw_Rectangle(441,23,477,63,White);	//反白RUN 
		Draw_Rectangle(442,24,476,62,White);		
		virtual_LCM_PutString(447,38,"RUN",White,Black,1);

		Draw_Rectangle(403,23,440,63,Magenta);	//改色STOP 
		Draw_Rectangle(404,24,439,62,Magenta);		
		virtual_LCM_PutString(407,38,"STOP",Magenta,Black,1);
		
		WaveCtrl.Stop = 1;
	}
	if(ZBX>60 && ZBX<80 && ZBY>220 && ZBY<250)  //RUN 449 475 58 86
	{
		Draw_Rectangle(403,23,440,63,White);	//同上…… 
		Draw_Rectangle(404,24,439,62,White);		
		virtual_LCM_PutString(407,38,"STOP",White,Black,1);

		Draw_Rectangle(441,23,477,63,Magenta);	 
		Draw_Rectangle(442,24,476,62,Magenta);		
		virtual_LCM_PutString(447,38,"RUN",Magenta,Black,1);
	 	
		WaveCtrl.Stop = 0;
	} 
	if(ZBX>100 && ZBX<130 && ZBY>180 && ZBY<210)  //AC 421 440 98 121
	{
		Draw_Rectangle(441,65,477,105,White);	 
		Draw_Rectangle(442,66,476,104,White);		
		virtual_LCM_PutString(450,78,"DC",White,Black,1);
		
		Draw_Rectangle(403,65,440,105,Magenta);	 
		Draw_Rectangle(404,66,439,104,Magenta);		
		virtual_LCM_PutString(415,78,"AC",Magenta,Black,1);
		
		JDQ_ACDC = 1;
	}
	if(ZBX>60 && ZBX<80 && ZBY>180 && ZBY<210)  //DC 449 475 98 121
	{
		Draw_Rectangle(403,65,440,105,White);	 
		Draw_Rectangle(404,66,439,104,White);		
		virtual_LCM_PutString(415,78,"AC",White,Black,1);

		Draw_Rectangle(441,65,477,105,Magenta);	 
		Draw_Rectangle(442,66,476,104,Magenta);		
		virtual_LCM_PutString(450,78,"DC",Magenta,Black,1);
	 	
		JDQ_ACDC = 0;
	} 
	if(ZBX>100 && ZBX<130 && ZBY>140 && ZBY<170)  //X+ 421 440 131 159 
	{
	 	WaveCtrl.TimeBase += 5;
		if(WaveCtrl.TimeBase >= 1000)
			WaveCtrl.TimeBase = 1000;
		TimeBaseControl(WaveCtrl.TimeBase);
	}
	if(ZBX>60 && ZBX<80 && ZBY>140 && ZBY<170)  //X- 449 475 131 159 
	{
	 	WaveCtrl.TimeBase -= 5;									  
		if(WaveCtrl.TimeBase <= 1)
			WaveCtrl.TimeBase = 1;
		TimeBaseControl(WaveCtrl.TimeBase);
	} 
	if(ZBX>100 && ZBX<130 && ZBY>100 && ZBY<130)  //Y+ 421 440 167 194
	{
		if(++WaveCtrl.Gain > 8)
	   		WaveCtrl.Gain = 1;
		ManualGainScan(WaveCtrl.Gain);
	}
	if(ZBX>60 && ZBX<80 && ZBY>100 && ZBY<130)  //Y- 449 475 167 194
	{
		if(--WaveCtrl.Gain < 1)
	   		WaveCtrl.Gain = 8;
		ManualGainScan(WaveCtrl.Gain);
	}
	if(ZBX>100 && ZBX<130 && ZBY>60 && ZBY<90)  //SIN 421 440 203 229
	{
		Draw_Rectangle(441,232,477,271,White);	 
		Draw_Rectangle(442,231,476,270,White);		
		virtual_LCM_PutString(447,245,"TRG",White,Black,1);

		Draw_Rectangle(441,192,477,230,White);	 
		Draw_Rectangle(442,193,476,229,White);		
		virtual_LCM_PutString(447,205,"SQU",White,Black,1);
		
		Draw_Rectangle(403,192,440,230,Magenta);	 
		Draw_Rectangle(404,193,439,229,Magenta);		
		virtual_LCM_PutString(410,205,"SIN",Magenta,Black,1);
//		Program Size: Code=61216 RO-data=8280 RW-data=340 ZI-data=30100
//		Program Size: Code=55724 RO-data=8268 RW-data=256 ZI-data=29912
//      Program Size: Code=55688 RO-data=6456 RW-data=256 ZI-data=25160      
	 	FunctionGenerator(Sine_Wave,3000,2.5,50);	
	}
	if(ZBX>60 && ZBX<80 && ZBY>60 && ZBY<90)  //SQU 449 475 203 229
	{
		Draw_Rectangle(441,232,477,271,White);	 
		Draw_Rectangle(442,231,476,270,White);		
		virtual_LCM_PutString(447,245,"TRG",White,Black,1);

		Draw_Rectangle(403,192,440,230,White);	 
		Draw_Rectangle(404,193,439,229,White);		
		virtual_LCM_PutString(410,205,"SIN",White,Black,1);

		Draw_Rectangle(441,192,477,230,Magenta);	 
		Draw_Rectangle(442,193,476,229,Magenta);		
		virtual_LCM_PutString(447,205,"SQU",Magenta,Black,1);
	 	
		FunctionGenerator(Triangle_Wave,3000,2.5,50);
	} 
	if(ZBX>100 && ZBX<130 && ZBY>0 && ZBY<52)  //AUTO 421 440 239 265 
	{	
		if(++TrackLine_Switch >	TRACKLINE_BOTH_OPEN)
			TrackLine_Switch = TRACKLINE_BOTH_CLOSE;	
		
		if(TrackLine_Switch == TRACKLINE_BOTH_CLOSE)
		{
			Draw_Rectangle(403,232,440,271,White);	 
			Draw_Rectangle(404,231,439,270,White);		
			virtual_LCM_PutString(407,245,"AUTO",White,Black,1);			
		}
		else
		{
		 	Draw_Rectangle(403,232,440,271,Magenta);	 
			Draw_Rectangle(404,231,439,270,Magenta);		
			virtual_LCM_PutString(407,245,"AUTO",Magenta,Black,1);
		}
	}
	if(ZBX>60 && ZBX<80 && ZBY>0 && ZBY<52)  //TRG 449 475 239 265
	{
		Draw_Rectangle(403,192,440,230,White);	 
		Draw_Rectangle(404,193,439,229,White);		
		virtual_LCM_PutString(410,205,"SIN",White,Black,1);

		Draw_Rectangle(441,192,477,230,White);	 
		Draw_Rectangle(442,193,476,229,White);		
		virtual_LCM_PutString(447,205,"SQU",White,Black,1);

		Draw_Rectangle(441,232,477,271,Magenta);	 
		Draw_Rectangle(442,231,476,270,Magenta);		
		virtual_LCM_PutString(447,245,"TRG",Magenta,Black,1);

		FunctionGenerator(Square_Wave,3000,2.5,50);
	 }
			PramPanel_Switch = 3;
}

 

 

 


六、作品演示

 https://v.qq.com/x/page/z05408c30kj.html

视频中使用了示波器的波形发生器功能,将波形输出端(STM32的一路DAC)接到信号输入端(STM32的一路ADC),显示示波器自己产生的标准波形,TRG表示方波,SQU表示三角波,SIN表示正弦波。X+,X-代表时基的加减,Y+,Y-代表增益的加减。AUTO代表自动触发。正常使用时,将外部信号源的信号端和接地端分别接到示波器的信号输入端和接地端即可。

七、总结

这个示波器只是个雏形,后续还会改进,毕竟只研究了一个月

这只是个低频示波器,学生党,为了省钱,没有用上高速运放,要想提高速度,加上FPGA可能会好一些,下一步准备学一学FPGA,示波器的显示界面有些单调,而且由于菜单键的占用一部分屏幕,波形显示区显得有些小,下一步考虑增加多界面切换显示功能,在功能增加的同时,STM32F103ZET6也越来越吃力,主控也要考虑升级,以便更好的做波形分析有关的运算

 

   

 

 


主题

回复
发表于2017-08-16 19:19:56   |  显示全部楼层
9#
很赞的一个设计

主题

回复
  • 温馨提示: 标题不合格、重复发帖、发布广告贴,将会被删除帖子或禁止发言。 详情请参考: 社区发帖规则
  • 您当前输入了 0 个文字。还可以输入 8000 个文字。 已添加复制上传图片功能,该功能目前仅支持chrome和火狐

禁言/删除

X
请选择禁言时长:
是否清除头像:
禁言/删除备注:
昵 称:
 
温馨提示:昵称只能设置一次,设置后无法修改。
只支持中文、英文和数字。

举报

X
请选择举报类型:
请输入详细内容:

顶部