⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dso.c

📁 STM32手持式示波器源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
* Copyright (C), 2010, www.armfly.com
*
* 【本例程在安富莱STM32F103ZE-EK开发板上调试通过             】
* 【QQ: 1295744630, 旺旺:armfly, Email: armfly@qq.com       】
*
* 文件名: dso.c
* 内容简述: 本模块完成示波器adc采样方面的工作
*
* 文件历史:
* 版本号  日期       作者    说明
* v0.1    2010-03-18 armfly  创建该文件
*
*/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include <string.h>
#include "tft_lcd.h"
#include "systick.h"
#include "dso.h"
#include "button.h"
#include "BackLight.h"
#include "WaveMaker.h"

#define DSO_VER	"V0.6"		  /* 当前版本 */

/* 主程序状态字 */
enum
{
	S_HELP		= 0,	/* 帮助页面 */
	S_RUN		= 1,	/* 采集状态 */
	S_HOLD		= 2		/* 暂停状态 */
};

/* 时间分度表, g_DSO.TimeBaseId作为数组索引  */
const uint32_t g_TimeTable[] =
{
	20, 	50, 	100, 
	200,	500,	1000,
	2000,	5000,	10000,
	20000,	50000,	100000,
	200000,	500000,	1000000		
};

/* 衰减倍数表  
	g_DSO.Ch1Attenuation = 23
	幅度衰减因子:
	(1) 28 === 1V  (1:1)
*/
#define ATT_COUNT	6
const uint32_t g_AttTable[ATT_COUNT][2] =
{
	/* {除数,每大格电压}  1:1 */
	{1400,	5000},
	{560,	2000},
	{280,	1000},
	{140,	500},
	{56,	200},
	{28,	100},
};

static void DsoHelp(uint8_t *pMainStatus);
static void DsoRun(uint8_t *pMainStatus);

/*
	安富莱STM32F103ZE-EK 口线分配:

	示波器通道1同时连接到CPU的PC0、PC2、PC3,这3个口线作为ADC输入使用
		PC0 = ADC1_IN10
		PC2 = ADC2_IN12
		PC3 = ADC3_IN13

	示波器通道2只连接到CPU的PC1,这个口线作为ADC输入使用
		PC1 = ADC2_IN12

	对于通道1的模拟信号,可以同时启动3个ADC进行交错采样,理论上可以实现3Mbps采样速率 
	(后来发现ADC2不能DMA操作,因此这句话还有待考究)

	通道2只能启动1个ADC进行采样。
	支持通道1和通道2进行同步采样。
*/

DSO_T g_DSO;	/* 全局变量,是一个结构体 */

/*******************************************************************************
*	函数名: DsoMain
*	输  入:	无
*	输  出:	无
*	功能说明:DSO主程序,是一个循环体
*/
void DsoMain(void)
{
	uint8_t MainStatus = S_RUN;		/* 程序执行状态 */

	InitWaveMaker();
//	SetupWaveType(WT_SIN);		/* 设置正弦波 */

	LCD_Init();		/* 显示器初始化 */

	SetBackLight(BRIGHT_DEFAULT);  /* 设置背光亮度 */

	/* 进入主程序循环体 */
	while (1)
	{
		switch (MainStatus)
		{
			case S_HELP:
				DsoHelp(&MainStatus);		/* 显示帮助 */
				break;

			case S_RUN:
				DsoRun(&MainStatus);		/* 全速采集,实时显示 */
				break;

			default:
				break;
		}
	}
}

/*******************************************************************************
*	函数名: InitDSO
*	输  入:	无
*	输  出:	无
*	功能说明:对示波器通道1进行初始化配置。主要完成GPIO的配置、ADC的配置、
*		定时器的配置以及DMA的配置。
*/
static void InitDSO(void)
{
	/* 配置GPIO.  */
	{
		GPIO_InitTypeDef GPIO_InitStructure;

		/* 打开GPIO_C 和 AFIO 的时钟 */
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC	| RCC_APB2Periph_AFIO, ENABLE);

		/* 配置PC0为模拟输入模式 */
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOC, &GPIO_InitStructure);
	}


	/* 配置DMA1_1 用于CH1 */
	#if 1
	{
		DMA_InitTypeDef DMA_InitStructure;

		/* Enable DMA1 clock */
		RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

		DMA_DeInit(DMA1_Channel1);		/* 复位DMA1寄存器到缺省状态 */
		DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;	/* 选择ADC1的数据寄存器作为源 */
		DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&g_DSO.Ch1Buf;	/* 目标地址 */
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	/* 设置DMA传输方向,外设(ADC)作为源 */
		DMA_InitStructure.DMA_BufferSize = SAMPLE_COUNT;	/* 设置缓冲区大小 */
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	/* 外设地址不自增 */
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	/* 存储器地址需要自增 */
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	/* 选择外设传输单位:16bit */
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	/* 选择内存传输单位:16bit */
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;	/* 无需循环模式   */
		DMA_InitStructure.DMA_Priority = DMA_Priority_High;	/* 选择DMA优先级 */
		DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	/* DMA传输类型,不是内存到内存 */
		DMA_Init(DMA1_Channel1, &DMA_InitStructure);

		/* Enable DMA1 channel1 */
		DMA_Cmd(DMA1_Channel1, ENABLE);
	}
	#endif

	/* 配置DMA2_5 用于CH2 */
	#if 1
	{
		DMA_InitTypeDef DMA_InitStructure;

		/* Enable DMA1 clock */
		RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

		DMA_DeInit(DMA2_Channel5);		/* 复位DMA2寄存器到缺省状态 */
		DMA_InitStructure.DMA_PeripheralBaseAddr = ADC3_DR_Address;	/* 选择ADC3的数据寄存器作为源 */
		DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&g_DSO.Ch2Buf;	/* 目标地址 */
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	/* 设置DMA传输方向,外设(ADC)作为源 */
		DMA_InitStructure.DMA_BufferSize = SAMPLE_COUNT;	/* 设置缓冲区大小 */
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	/* 外设地址不自增 */
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	/* 存储器地址需要自增 */
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	/* 选择外设传输单位:16bit */
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	/* 选择内存传输单位:16bit */
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;	/* 无需循环模式   */
		DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;	/* 选择DMA优先级 */
		DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	/* DMA传输类型,不是内存到内存 */
		DMA_Init(DMA2_Channel5, &DMA_InitStructure);

		/* Enable DMA2 channel5 */
		DMA_Cmd(DMA2_Channel5, ENABLE);
	}
	#endif

	/* 配置ADC1  */
	
	 /* ADCCLK = PCLK2/2 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div2);     //ADCCLK = PCLK2/4 = 18MHz

	#if 1
	{
		ADC_InitTypeDef	ADC_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

		ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
		ADC_InitStructure.ADC_ScanConvMode = DISABLE;
		ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		/* 连续转换静止 */
		ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3;	/* 选择TIM1的CC3做触发 */
		//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;	/* 选择TIM2的CC2做触发 */

		ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	/* 数据右对齐,高位为0 */
		ADC_InitStructure.ADC_NbrOfChannel = 1;	/* 1个通道 */
		ADC_Init(ADC1, &ADC_InitStructure);

		/* ADC1 regular channels configuration */
		ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_1Cycles5);

		/* Enable ADC1 external trigger conversion */
		ADC_ExternalTrigConvCmd(ADC1, ENABLE);

		/* 使能 ADC1 */
		ADC_Cmd(ADC1, ENABLE);

		/* Enable ADC1 DMA */
		ADC_DMACmd(ADC1, ENABLE);

		/* 使能 ADC1 复位校准寄存器 */
		ADC_ResetCalibration(ADC1);
		/* 检测复位校准寄存器 */
		while(ADC_GetResetCalibrationStatus(ADC1));

		/* 开始 ADC1 校准 */
		ADC_StartCalibration(ADC1);
		/* 等待校准结束 */
		while(ADC_GetCalibrationStatus(ADC1));
	}
	#endif

	/* 配置ADC3  */
	#if 1
	{
		ADC_InitTypeDef	ADC_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

		ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
		ADC_InitStructure.ADC_ScanConvMode = DISABLE;
		ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		/* 连续转换静止 */
		//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;	/* 选择TIM1的CC1做触发 */
		ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3;	/* 选择TIM2的CC2做触发 */
		ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	/* 数据右对齐,高位为0 */
		ADC_InitStructure.ADC_NbrOfChannel = 1;	/* 1个通道 */
		ADC_Init(ADC3, &ADC_InitStructure);

		/* ADC1 regular channels configuration */
		ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_1Cycles5);

		/* Enable ADC3 external trigger conversion */
		ADC_ExternalTrigConvCmd(ADC3, ENABLE);

		/* 使能 ADC3 */
		ADC_Cmd(ADC3, ENABLE);

		/* Enable ADC3 DMA */
		ADC_DMACmd(ADC3, ENABLE);

		/* 使能 ADC3 复位校准寄存器 */
		ADC_ResetCalibration(ADC3);
		/* 检测复位校准寄存器 */
		while(ADC_GetResetCalibrationStatus(ADC3));

		/* 开始 ADC3 校准 */
		ADC_StartCalibration(ADC3);
		/* 等待校准结束 */
		while(ADC_GetCalibrationStatus(ADC3));
	}
	#endif

	/* 配置采样触发定时器,使用TIM1 CC1 */
	SetSampRate(g_DSO.SampleFreq);	/* 修改采样频率(启动时100K) */
}

/*******************************************************************************
*	函数名: SetSampRate
*	输  入:	freq : 采样频率 单位Hz
*	输  出:
*	功  能:修改采样频率
*/
static void SetSampRate(uint32_t freq)
{
	/* 第4步: 配置定时器2第2通道CC2, CC2作为ADC1的触发源 */
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	uint16_t Period;

	TIM_Cmd(TIM1, DISABLE);

//	g_DSO.SampleRate = freq;	/* 将采样频率保存到全部变量中 */

	/*
	采样频率计算公式 :
		period = 72000000 / freq ;
		
		1200 == 60KHz 采样频率
	*/
	Period = 72000000 / freq;		

	/* Enable TIM1 clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
	TIM_TimeBaseStructure.TIM_Period = Period;          
	TIM_TimeBaseStructure.TIM_Prescaler = 0;   /* 计数频率 = 72000 000 / 18 = 4000 000	 */
	TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	/* TIM1 channel1 configuration in PWM mode */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;                
	TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period / 2; 
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;         
	TIM_OC3Init(TIM1, &TIM_OCInitStructure);

	/* TIM1 counter enable */
	TIM_Cmd(TIM1, ENABLE);

	/* TIM1 main Output Enable */
	TIM_CtrlPWMOutputs(TIM1, ENABLE);  
}

static void DispHelp1(void)
{
	uint16_t y;
	uint16_t LineCap;

	LCD_Clear(Blue);  			/* 清屏,背景蓝色 */
	LCD_SetBackColor(Blue);		/* 设置文字背景颜色 */

	LCD_SetTextColor(White);	/* 设置文字颜色 */
	y = 0;
	LineCap = 18; /* 行间距 */
	LCD_DisplayString(20, y, "安富莱STM32F103ZE-EK开发板  www.armfly.com");
	y += LineCap;
	LCD_SetTextColor(Yellow);
	LCD_DisplayString(30, y, "QQ:1295744630     Email:armfly@qq.com");
	y += LineCap;

	y += LineCap;

	LCD_DisplayString(30, y, "操作提示:");
	y += LineCap;
	LCD_DisplayString(50, y, "TAMPER键 = 切换通道焦点。CH1或CH2");
	y += LineCap;
	LCD_DisplayString(50, y, "WAKEUP键 = 显示帮助或退出帮助");
	y += LineCap;
	LCD_DisplayString(50, y, "USER  键 = 暂停或实时运行");
	y += LineCap;
	LCD_DisplayString(50, y, "摇杆上键 = 放大波形垂直幅度或向上移动");
	y += LineCap;
	LCD_DisplayString(50, y, "摇杆下键 = 缩小波形垂直幅度或向下移动");
	y += LineCap;
	LCD_DisplayString(50, y, "摇杆左键 = 水平展宽波形");
	y += LineCap;
	LCD_DisplayString(50, y, "摇杆右键 = 水平缩小波形");
	y += LineCap;
	LCD_DisplayString(50, y, "摇杆OK键 = 切换摇杆调节模式。幅度或位置");
	y += LineCap;
}

/*******************************************************************************
*	函数名: DsoHelp
*	输  入:	无
*	输  出:	无
*	功  能:显示帮助
*/
static void DsoHelp(uint8_t *pMainStatus)
{
	uint8_t KeyCode;
	uint16_t bright;
	uint8_t fRefresh = 1;	/* LCD刷新标志 */
	uint8_t SubStatus = 0;

	bright = GetBackLight();	/* 读取背光值 */
	while (*pMainStatus == S_HELP)
	{
		CPU_IDLE();

		if (fRefresh)
		{
			fRefresh = 0;

			if (SubStatus == 0)
			{
				DispHelp1();
			}
		}

		/* 读取按键,大于0表示有键按下 */
		KeyCode = GetKey();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -