?? dso.c
字號:
/****************************************************************************
* Copyright (C), 2010, www.armfly.com
*
* 【本例程在安富萊STM32F103ZE-EK開發(fā)板上調(diào)試通過 】
* 【QQ: 1295744630, 旺旺:armfly, Email: armfly@qq.com 】
*
* 文件名: dso.c
* 內(nèi)容簡述: 本模塊完成示波器adc采樣方面的工作
*
* 文件歷史:
* 版本號 日期 作者 說明
* v0.1 2010-03-18 armfly 創(chuàng)建該文件
*
*/
/* 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" /* 當(dāng)前版本 */
/* 主程序狀態(tài)字 */
enum
{
S_HELP = 0, /* 幫助頁面 */
S_RUN = 1, /* 采集狀態(tài) */
S_HOLD = 2 /* 暫停狀態(tài) */
};
/* 時(shí)間分度表, g_DSO.TimeBaseId作為數(shù)組索引 */
const uint32_t g_TimeTable[] =
{
20, 50, 100,
200, 500, 1000,
2000, 5000, 10000,
20000, 50000, 100000,
200000, 500000, 1000000
};
/* 衰減倍數(shù)表
g_DSO.Ch1Attenuation = 23
幅度衰減因子:
(1) 28 === 1V (1:1)
*/
#define ATT_COUNT 6
const uint32_t g_AttTable[ATT_COUNT][2] =
{
/* {除數(shù),每大格電壓} 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同時(shí)連接到CPU的PC0、PC2、PC3,這3個(gè)口線作為ADC輸入使用
PC0 = ADC1_IN10
PC2 = ADC2_IN12
PC3 = ADC3_IN13
示波器通道2只連接到CPU的PC1,這個(gè)口線作為ADC輸入使用
PC1 = ADC2_IN12
對于通道1的模擬信號,可以同時(shí)啟動3個(gè)ADC進(jìn)行交錯(cuò)采樣,理論上可以實(shí)現(xiàn)3Mbps采樣速率
(后來發(fā)現(xiàn)ADC2不能DMA操作,因此這句話還有待考究)
通道2只能啟動1個(gè)ADC進(jìn)行采樣。
支持通道1和通道2進(jìn)行同步采樣。
*/
DSO_T g_DSO; /* 全局變量,是一個(gè)結(jié)構(gòu)體 */
/*******************************************************************************
* 函數(shù)名: DsoMain
* 輸 入: 無
* 輸 出: 無
* 功能說明:DSO主程序,是一個(gè)循環(huán)體
*/
void DsoMain(void)
{
uint8_t MainStatus = S_RUN; /* 程序執(zhí)行狀態(tài) */
InitWaveMaker();
// SetupWaveType(WT_SIN); /* 設(shè)置正弦波 */
LCD_Init(); /* 顯示器初始化 */
SetBackLight(BRIGHT_DEFAULT); /* 設(shè)置背光亮度 */
/* 進(jìn)入主程序循環(huán)體 */
while (1)
{
switch (MainStatus)
{
case S_HELP:
DsoHelp(&MainStatus); /* 顯示幫助 */
break;
case S_RUN:
DsoRun(&MainStatus); /* 全速采集,實(shí)時(shí)顯示 */
break;
default:
break;
}
}
}
/*******************************************************************************
* 函數(shù)名: InitDSO
* 輸 入: 無
* 輸 出: 無
* 功能說明:對示波器通道1進(jìn)行初始化配置。主要完成GPIO的配置、ADC的配置、
* 定時(shí)器的配置以及DMA的配置。
*/
static void InitDSO(void)
{
/* 配置GPIO. */
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 打開GPIO_C 和 AFIO 的時(shí)鐘 */
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); /* 復(fù)位DMA1寄存器到缺省狀態(tài) */
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; /* 選擇ADC1的數(shù)據(jù)寄存器作為源 */
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&g_DSO.Ch1Buf; /* 目標(biāo)地址 */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /* 設(shè)置DMA傳輸方向,外設(shè)(ADC)作為源 */
DMA_InitStructure.DMA_BufferSize = SAMPLE_COUNT; /* 設(shè)置緩沖區(qū)大小 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* 外設(shè)地址不自增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /* 存儲器地址需要自增 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /* 選擇外設(shè)傳輸單位:16bit */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /* 選擇內(nèi)存?zhèn)鬏攩挝唬?6bit */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* 無需循環(huán)模式 */
DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* 選擇DMA優(yōu)先級 */
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /* DMA傳輸類型,不是內(nèi)存到內(nèi)存 */
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); /* 復(fù)位DMA2寄存器到缺省狀態(tài) */
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC3_DR_Address; /* 選擇ADC3的數(shù)據(jù)寄存器作為源 */
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&g_DSO.Ch2Buf; /* 目標(biāo)地址 */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /* 設(shè)置DMA傳輸方向,外設(shè)(ADC)作為源 */
DMA_InitStructure.DMA_BufferSize = SAMPLE_COUNT; /* 設(shè)置緩沖區(qū)大小 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* 外設(shè)地址不自增 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /* 存儲器地址需要自增 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /* 選擇外設(shè)傳輸單位:16bit */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /* 選擇內(nèi)存?zhèn)鬏攩挝唬?6bit */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* 無需循環(huán)模式 */
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; /* 選擇DMA優(yōu)先級 */
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /* DMA傳輸類型,不是內(nèi)存到內(nèi)存 */
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; /* 連續(xù)轉(zhuǎn)換靜止 */
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3; /* 選擇TIM1的CC3做觸發(fā) */
//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; /* 選擇TIM2的CC2做觸發(fā) */
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; /* 數(shù)據(jù)右對齊,高位為0 */
ADC_InitStructure.ADC_NbrOfChannel = 1; /* 1個(gè)通道 */
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 復(fù)位校準(zhǔn)寄存器 */
ADC_ResetCalibration(ADC1);
/* 檢測復(fù)位校準(zhǔn)寄存器 */
while(ADC_GetResetCalibrationStatus(ADC1));
/* 開始 ADC1 校準(zhǔn) */
ADC_StartCalibration(ADC1);
/* 等待校準(zhǔn)結(jié)束 */
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; /* 連續(xù)轉(zhuǎn)換靜止 */
//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; /* 選擇TIM1的CC1做觸發(fā) */
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3; /* 選擇TIM2的CC2做觸發(fā) */
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; /* 數(shù)據(jù)右對齊,高位為0 */
ADC_InitStructure.ADC_NbrOfChannel = 1; /* 1個(gè)通道 */
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 復(fù)位校準(zhǔn)寄存器 */
ADC_ResetCalibration(ADC3);
/* 檢測復(fù)位校準(zhǔn)寄存器 */
while(ADC_GetResetCalibrationStatus(ADC3));
/* 開始 ADC3 校準(zhǔn) */
ADC_StartCalibration(ADC3);
/* 等待校準(zhǔn)結(jié)束 */
while(ADC_GetCalibrationStatus(ADC3));
}
#endif
/* 配置采樣觸發(fā)定時(shí)器,使用TIM1 CC1 */
SetSampRate(g_DSO.SampleFreq); /* 修改采樣頻率(啟動時(shí)100K) */
}
/*******************************************************************************
* 函數(shù)名: SetSampRate
* 輸 入: freq : 采樣頻率 單位Hz
* 輸 出:
* 功 能:修改采樣頻率
*/
static void SetSampRate(uint32_t freq)
{
/* 第4步: 配置定時(shí)器2第2通道CC2, CC2作為ADC1的觸發(fā)源 */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t Period;
TIM_Cmd(TIM1, DISABLE);
// g_DSO.SampleRate = freq; /* 將采樣頻率保存到全部變量中 */
/*
采樣頻率計(jì)算公式 :
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; /* 計(jì)數(shù)頻率 = 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); /* 清屏,背景藍(lán)色 */
LCD_SetBackColor(Blue); /* 設(shè)置文字背景顏色 */
LCD_SetTextColor(White); /* 設(shè)置文字顏色 */
y = 0;
LineCap = 18; /* 行間距 */
LCD_DisplayString(20, y, "安富萊STM32F103ZE-EK開發(fā)板 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鍵 = 切換通道焦點(diǎn)。CH1或CH2");
y += LineCap;
LCD_DisplayString(50, y, "WAKEUP鍵 = 顯示幫助或退出幫助");
y += LineCap;
LCD_DisplayString(50, y, "USER 鍵 = 暫?;?qū)崟r(shí)運(yùn)行");
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鍵 = 切換搖桿調(diào)節(jié)模式。幅度或位置");
y += LineCap;
}
/*******************************************************************************
* 函數(shù)名: DsoHelp
* 輸 入: 無
* 輸 出: 無
* 功 能:顯示幫助
*/
static void DsoHelp(uint8_t *pMainStatus)
{
uint8_t KeyCode;
uint16_t bright;
uint8_t fRefresh = 1; /* LCD刷新標(biāo)志 */
uint8_t SubStatus = 0;
bright = GetBackLight(); /* 讀取背光值 */
while (*pMainStatus == S_HELP)
{
CPU_IDLE();
if (fRefresh)
{
fRefresh = 0;
if (SubStatus == 0)
{
DispHelp1();
}
}
/* 讀取按鍵,大于0表示有鍵按下 */
KeyCode = GetKey();
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -