目录
2系统方案设计 6
2.1 数字示波器的工作原理 6
2.2 数字示波器的重要技术指标 6
2.3 系统方案论证与比较 8
2.4 系统性能指标设计 9
3 系统硬件设计 12
3.1 耦合电路设计 12
3.2 信号调理电路设计 13
3.2.1 衰减网络电路设计 13
3.2.2 程控放大电路设计 14
3.3 高速A/D采集与FIFO缓存电路设计 15
3.4 测频整形电路设计 16
3.5 电源电路设计 17
3.6 微处理器最小系统电路设计 18
3.7 按键电路设计 19
3.8 液晶显示电路设计 19
本设计描述了一款嵌入式数字示波器,在硬件上采用了32位微处理器STM32和高速A/D转换器ADS830等器件,软件上搭载上µC/OS-II实时操作系统,简化编程,提高系统的效率和稳定性。输入信号从系统的无源探头接入,先经过的是AC/DC耦合电路,然后经过信号调理电路,被调理后的信号接着由A/D转换器转变成数字信号,再经过高速缓存器FIFO,信号数据即被传送到微处理器STM32中,由微处理器STM32完成对信号数据的处理,最后把波形还原到液晶上,并显示该信号的频率、电压等技术指标,本文转载自http://www.biyezuopin.vip/onews.asp?id=12695以供用户参考。
3、主要元器件列表
(1)STM32F103VCT6(主控制器)
(2)ADS830(高速A/D)
(3)IDT7204(高速缓存,FIFO)
(4)AD603(程控放大)
(5)AD8066(FET高速高性能放大器)
(6)TLV5618(双路12位串行DAC)
4、主体方案思路
如图所示:
/*includes----------------------------------------------------------------*/
#include "ad.h"
/* 定义一个结构体,全局变量 */
OSC ad;
/*define variables -------------------------------------------------------*/
/*-------主程序状态字-------*/
// enum
// {
// StateHelp = 0; //帮助
// StateRun = 1; //采集
// StateHold = 2 //暂停
// }
/*-------时间分度表,即每一格是多少时间,DSO.TimeBaseID 作为数组索引------*/
const uint32_t TimeTable[]=
{
20 ,50 ,100,
200 ,500 ,1000,
2000 ,50000,10000,
20000,50000,100000
};
/*--------衰减倍数 ,每大格电压--------*/
const uint32_t AttTable[][2]=
{
{1400,5000},
{560 ,2000},
{280 ,1000},
{140 ,500 },
{56 ,200 },
{28 ,100 }
};
static void DsoHelp(uint8_t *MainStatus);
static void DsoRun(uint8_t *MainStatus);
/********************************************************************************
**function name:DSO_Run
**description : DSO 全速运行
**input :none
**output :none
**return :none
**attention :none
*****************************************************************************/
static void OscRun(uint8_t *MainStatus)
{
uint8_t Fresh_flag = 1; //TFT 刷新标志
InitDsoParam(); //初始化示波器参数
InitDso(); //配置外设 ADC,DMA,TIM
SSD1289_FullScreen(Blue);//背景颜色:蓝色
Timer_Fresh(); //定时器1刷新,100ms 刷新一次
while(*MainStatus == StateRun)
{
}
}
/********************************************************************************
**function name:DSO_Init
**description : 对ADC的GPIO、ADC、定时器和DMA的配置
PC0 = ADC1_IN10
PC3 = ADC2_IN11
GPIO的输入模式设置为模拟输入AIN
**input :none
**output :none
**return :none
**attention :none
*****************************************************************************/
void DSO_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*enable the clock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_Init(GPIOC,&GPIO_InitStructure);
/*config the DMA1 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1|RCC_AHBPeriph_DMA2,ENABLE);
/*因为ADC1是通过DMA1的五个通道中的通道1连接到DMA1的,所以事先要清除通道1*/
DMA_DeInit(DMA1_Channel1);
/* 选择ADC1的数据寄存器作为源 */
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
/* 目标地址 */
DMA_InitStructure.DMA_MemoryBaseAddr = (u16)&DSO.AD_value;
/* 设置DMA传输方向,外设(ADC)作为源 */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
/* 设置缓冲区大小 */
DMA_InitStructure.DMA_BufferSize = Sample_count;
/* 外设地址不自增 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* 存储器地址需要自增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 选择外设传输单位:16bit */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
/* 选择内存传输单位:16bit */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
/* 无需循环模式 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
/* 选择DMA优先级 */
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
/* DMA传输类型,不是内存到内存 */
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
/*enable DMA1 to channel1*/
DMA_Cmd(DMA1_Channel1,ENABLE);
/* 配置DMA2_5 用于CH2 */
/* Enable DMA2 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
DMA_DeInit(DMA2_Channel5); /* 复位DMA2寄存器到缺省状态 */
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC3_DR_Address; /* 选择ADC3的数据寄存器作为源 */
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ad.CH2buffer; /* 目标地址 */
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);
/*ADC1 Configuration*/
/*enable the clock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
/*ADCCLK=PCLK2/6=12MHz*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExteralTrigConv_T1_CC3; //选择T1的捕获比较CC3作为触发源
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐,高位为0
ADC_InitStructure.ADC_NbrOfChannel = 1; //采集通道数目为1
ADC_Init(ADC1, &ADC_InitStructure);
/*ADC1 regular external trigger conversion ,sample_time = 1.5 cycle*/
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_1Cycles5);
/*enable ADC1 external trigger conversion */
ADC_ExternalTrigConvCmd(ADC1,ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
/* 使能 ADC1 复位校准寄存器 */
ADC_ResetCalibration(ADC1);
/* 检测复位校准寄存器 */
while(ADC_GetResetCalibrationStatus(ADC1));
/* 开始 ADC1 校准 */
ADC_StartCalibration(ADC1);
/* 等待校准结束 */
while(ADC_GetCalibrationStatus(ADC1));
/*ADC3 是通过DMA2的通道5连接到DMA2的*/
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_CC3; /* 选择TIM1的CC3做触发 */
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_13, 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));
/*配置采样触发定时器,使用TIM CC1*/
/*修改采样频率*/
Sample_Rate(ad.SampleFre);
}
/*************************************************************************
**function name:Sample_Rate
**description : 修改ADC的采样频率
配置定时器1第3通道CC3作为ADC1的触发源,工作在PWM模式
**input : U32 frequency 采样频率,单位Hz
**output : none
**return : none
**attention : none
**************************************************************************/
void SetSampleRate(u32 frequency)
{
/*时基结构体和比较输出结构体定义*/
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/*定义定时器的工作周期*/
u16 period;
/* 采样频率计算公式 : period = 72000000 / freq */
period=72000000/frequency;
TIM_Cmd(TIM1, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = period;
/*预分频: 不分频,那么计数频率 = 72000 000 / 18 = 4000 000*/
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
/*向上计数模式*/
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
/*初始化定时器1*/
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
/* 比较/PWM 通道的值*/
TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period / 2;
/*设置输出有效的高低电平,这里是低有效*/
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
/*比较输出设置为定时器1*/
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
/*定时器计数使能*/
TIM_Cmd(TIM1,ENABLE);
/*TIM1 主要输出使能*/
TIM_CtrlPWMOutputs(TIM1,ENABLE);
}
/*************************************************************************
**function name:Stop_ADC
**description : 暂停采样
**input : none
**output : none
**return : none
**attention : none
**************************************************************************/
void Stop_ADC(void)
{
/*禁用TIM1*/
TIM_Cmd(TIM1,DISABLE);
/*禁用DMA1 channel 1 和DMA2 channel 5*/
DMA_Cmd(DMA1_Channel1,DISABLE);
DMA_Cmd(DMA2_Channel5,DISABLE);
}
/*************************************************************************
**function name: Start_ADC
**description : 开始采样
**input : none
**output : none
**return : none
**attention : none
**************************************************************************/
void Start_ADC(void)
{
/*启动TIM1*/
TIM_Cmd(TIM1,ENABLE);
/*启动DMA1 channel 1 和DMA2 channel 5*/
DMA_Cmd(DMA1_Channel1,ENABLE);
DMA_Cmd(DMA2_Channel5,ENABLE);
}
/*************************************************************************
**function name: Draw_Wave
**description : 开始画示波器波形
**input : none
**output : none
**return : none
**attention : none
**************************************************************************/
void Draw_Wave(void)
{
u8 i,m,n;
u8 x=7,y=16;
u8 buffer_CH1[240];
/*缓冲区1数据用完了,马上用缓冲区2 的数据
if(ad.BufUsed==0)
{
ad.BufUsed=1;
}
else
{
ad.BufUsed=0;
}
*/
for(i=0;i<240;i++)
{
buffer_CH1[i]=(u8)(0.05*(ad.CH1buffer[i]));
}
for(i=0;i<240;i++)
{
if( buffer_CH1[i]< buffer_CH1[i+1])
{
for(n=buffer_CH1[i];n< buffer_CH1[i+1];n++)
{
m=y+n;
SSD1289_SetCursor(x,m);
SSD1289_WriteColor(Red);
m=0;
}
}
else if( buffer_CH1[i]== buffer_CH1[i+1])
{
m=y+ buffer_CH1[i];
SSD1289_SetCursor(x,m);
SSD1289_WriteColor(Red);
m=0;
}
else
{
for(n= buffer_CH1[i];n> buffer_CH1[i+1];n--)
{
m=y+n;
SSD1289_SetCursor(x,m);
SSD1289_WriteColor(Red);
m=0;
}
}
x++;
}
}
/*************************************************************************
**function name: Display_Wave
**description : display wave
**input : none
**output : none
**return : none
**attention : none
**************************************************************************/
static void Display_Wave(void)
{
static u8 Display_First = 0; //第一次调用时刷屏
if(Display_First == 0)
{
Display_First = 1;
SSD1289_FullScreen(Blue); //背景是蓝色
}
}
void display_adc1(void)
{
u8 num[5]={'0','0','0','0'};
num[0]=(u8)(ADC1ConvertedValue/1000+0x30);
num[1]=(u8)(ADC1ConvertedValue%1000/100+0x30);
num[2]=(u8)(ADC1ConvertedValue%100/10+0x30);
num[3]=(u8)(ADC1ConvertedValue%10+0x30);
SSD1289_DisplayString(7,223,num,Blue2,Grey);
}