引言?
寒假練有一款白色的、非常美觀的、雙通道輸入的基于STM32G031的板卡,它可以實(shí)現(xiàn)哪些功能呢?示波器、DDS信號(hào)發(fā)生器、頻譜分析儀、失真度測(cè)量?jī)x等等。 今天我們來(lái)看一位來(lái)自南京大學(xué)的【電子卷卷怪】同學(xué)所做的雙通道簡(jiǎn)易示波器項(xiàng)目,這位同學(xué)還幫助多個(gè)參加寒假練的同學(xué)親自解決了他們的問(wèn)題。項(xiàng)目成果概述?
本項(xiàng)目使用硬禾課堂STM32G031開發(fā)板卡以及STM32CubeIDE開發(fā)工具,實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的示波器。示波器的各項(xiàng)參數(shù)或功能概述如下:
1. 外觀(1)有主界面、副界面兩個(gè)界面,并可以相互切換;(2)主界面包含波形模式和FFT模式,分別顯示被測(cè)信號(hào)的波形和頻譜;(3)波形模式包含:垂直尺度調(diào)整、水平時(shí)基調(diào)整、屏幕中心電平調(diào)整、模擬觸發(fā)電平調(diào)整、負(fù)時(shí)間調(diào)整、平均值顯示、頻率測(cè)量顯示、峰峰值顯示;FFT模式包含:垂直尺度顯示、采樣率顯示、屏幕中心電平顯示、模擬觸發(fā)電平顯示、頻譜最大分量(歸一化值)顯示、頻標(biāo)調(diào)整、頻標(biāo)對(duì)應(yīng)分量顯示。(4)副界面包含5個(gè)其他功能:通道選擇、波形/FFT模式切換、開啟AUTO、模擬觸發(fā)電平極性、開啟單次(Single)模式。 2. 操作(1)位于主界面的任意模式時(shí),單擊左右鍵可以使光標(biāo)在該模式下可調(diào)整的功能間移動(dòng),轉(zhuǎn)動(dòng)旋鈕調(diào)整被光標(biāo)選中的參數(shù);(2)位于副界面時(shí),單擊左右鍵可以使光標(biāo)在5個(gè)其他功能間移動(dòng),轉(zhuǎn)動(dòng)旋鈕可以調(diào)整被選中的功能;(3)按住旋鈕的情況下:?jiǎn)螕糇箧I進(jìn)入主界面、單擊右鍵進(jìn)入副界面。(4)開啟AUTO后,自適應(yīng)調(diào)整只會(huì)在切回主界面后被執(zhí)行一次;對(duì)新波形的自適應(yīng)調(diào)整需要切到副界面——開啟AUTO——切回主界面。(5)開啟Single后,無(wú)觸發(fā)時(shí),正常顯示波形;觸發(fā)一次后,波形與頻譜均固定,并不會(huì)更新,但可以調(diào)整負(fù)時(shí)間和頻標(biāo);在觸發(fā)后,調(diào)整垂直尺度、水平時(shí)基、屏幕中心電平、模擬觸發(fā)電平、采樣率中的任意一者,都會(huì)導(dǎo)致下一次觸發(fā)的捕捉。![c1df0578-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9veASgB3AAG-WRI7ySA357.jpg)
![c1efe028-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9veADHgsAAGmupJiLN0484.jpg)
![c20750d2-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9veAdZITAAFAQiUkfiQ958.jpg)
項(xiàng)目需求分析?
總的來(lái)說(shuō),本項(xiàng)目可以分為兩個(gè)大的模塊:GUI模塊、采樣處理模塊。其中,相對(duì)于程序的主循環(huán)而言,采樣處理模塊是高速的、“同步”的,GUI模塊是慢速的、“異步”的。兩個(gè)模塊間既需要并行不悖,又需要互相交換數(shù)據(jù)。 對(duì)于采樣處理模塊,主要考慮以下4個(gè)需求問(wèn)題:1. ADC可控采樣率與切換通道的實(shí)現(xiàn);2. 觸發(fā)電平的實(shí)現(xiàn),以及負(fù)時(shí)間顯示的實(shí)現(xiàn);3. 如何對(duì)頻率進(jìn)行較高精度的測(cè)定;4. 如何計(jì)算信號(hào)頻譜; 對(duì)于GUI模塊,主要考慮以下3個(gè)需求問(wèn)題:1. 如何以盡可能低的誤判率獲取按鍵與旋鈕的信息;2. 中斷服務(wù)函數(shù)所應(yīng)干涉的范圍;3. 如何以盡可能簡(jiǎn)潔的方式實(shí)現(xiàn)按鍵對(duì)GUI的改變 對(duì)于兩個(gè)模塊而言,最核心的問(wèn)題是:如何在兩者之間進(jìn)行高效的數(shù)據(jù)傳輸?shù)耐瑫r(shí),避免數(shù)據(jù)的誤判或漏判。核心技術(shù)路線?
針對(duì)“二”中提出的需求,以下同樣分兩個(gè)模塊,對(duì)項(xiàng)目的技術(shù)路線進(jìn)行完備的論述。鑒于HAL庫(kù)過(guò)于龐大,且本人對(duì)項(xiàng)目的理解更偏重于硬件底層,除了HAL_Init,SystemClock_Config,以及與NVIC有關(guān)的3個(gè)最底層的函數(shù)(Priority, Enable, ClearPending)外,其他所有的外設(shè)配置代碼,均為本人閱讀器件手冊(cè)后編寫的寄存器代碼。1. ADC可控采樣率與通道切換在ADC連續(xù)模式下,雖然可以通過(guò)調(diào)整采樣時(shí)間來(lái)調(diào)整采樣率,但這樣做顯然并不好。一方面,這樣得到的轉(zhuǎn)換周期(Tsamp + 12.5ADC_Cycle)的倒數(shù),即頻率,往往是不規(guī)律的非整數(shù),這樣做不利于功能調(diào)整的層次化與統(tǒng)一化;另一方面,即使采用16MHz主頻,在12位分辨率下,ADC最小轉(zhuǎn)化頻率也有16MHz / (160.5 + 12.5) ≈92.5kHz,有效測(cè)量范圍太小。 定時(shí)器觸發(fā)的方式是最好的選擇。一方面,只需控制轉(zhuǎn)換時(shí)間不大于采樣率的倒數(shù),就能獲得完全可控的轉(zhuǎn)換率;另一方面,這樣有利于定時(shí)器觸發(fā)DMA傳輸?shù)囊搿S捎谠?2MHz主頻下,即使是最簡(jiǎn)單的中斷服務(wù)函數(shù),頻率也只能到150kHz左右,因此,DMA傳輸既可以提供較高的采樣率,又可以使“采樣——處理”分離的結(jié)構(gòu)更加清晰。配置的方法: 對(duì)ADC端:模擬看門狗的配置將在后面說(shuō)明。這里最關(guān)鍵的,一是必須配置為非連續(xù)模式、外部上升沿觸發(fā),選擇TIM2的TRGO為觸發(fā)源,并且不能選擇ADC為DMA觸發(fā)源,否則ADC的overwritten特性會(huì)迫使軟件屢屢清除標(biāo)志位,以保證DMA Request的持續(xù)產(chǎn)生;二是在外部觸發(fā)時(shí),必須先start。void ADC_init(void)
{
uint32_t temp;
RCC->IOPENR |= 0X1UL;//打開PortA時(shí)鐘
temp=RCC->IOPENR;//時(shí)鐘使能需等2個(gè)周期
UNUSED(temp);//避免Warning
//由于GPIOA->MODER對(duì)應(yīng)位默認(rèn)為0X3,即模擬輸入
//因此不需要再額外配置PortA
RCC->APBENR2 |= (0X1UL<<20UL);//打開ADC1時(shí)鐘
temp=RCC->APBENR2;
UNUSED(temp);
ADC1->CR |= (0X1UL<<28UL);//使能內(nèi)部參考電壓
//自己寫的延時(shí),用TIM17的OPM模式
TIM17_Delay(1000-1,32-1);//等待參考電壓有效
ADC1->CR |= (0X1UL<<31UL);
do
{
temp=ADC1->CR;//開始校正指令
}while(temp & (0X1UL<<31));//等待校正結(jié)束
ADC1->CFGR1 |= (0X1UL<<16 | 0X1UL<<12 | 0X2UL<<10 | 0X2UL<<6 | 0X0UL);
//(discontinuous,overwritten,ext rising edge,TRG2,DMA disabled);
ADC1->TR1 &= ~(0X0FFF0000);
ADC1->TR1 |= (0X0FFF0800);
//模擬看門狗的高低閾值
ADC1->CFGR1 |= (0X1<<26 | 0X1<<22 | 0X1UL<<23);
//AWD1 configuration
ADC1->CFGR2 |= (0X3UL<<30); //PCLK as ADC_CLK
ADC1->CHSELR |= (0X1UL << 1 | 0X0UL<<7);//選擇通道一
do
{
temp=ADC1->ISR;
}while(!(temp & (0X1UL<<13)));//等待通道配置有效
ADC1->CR |= 0X1UL;//enabling ADC1
do
{
temp = ADC1->ISR;
}while(!(temp & 0X1UL));//ADC Ready
ADC1->CR |= 0X1UL<<2;//ADC Start
return;
}
![c222cc36-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9veAOucXAAA1tAOoIyU887.jpg)
![c24857e4-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9veACS8qAAA3Ksv3ygo512.jpg)
傳輸數(shù)據(jù)使用的是通道一。相比于F407等系列,G031引入了DMAMUX的概念,使得幾乎所有的外設(shè)和一些事件都可以在任意一個(gè)DMA通道上產(chǎn)生請(qǐng)求。由于DMAMUX的0~4對(duì)應(yīng)DMA的1~5,查閱用戶指南后,得知設(shè)置DMAMUX的CCR的低7位為31(0X1F)表示TIM2的Update。 對(duì)TIM端:void ADC_DMA_init(void)
{
uint32_t temp;
RCC->AHBENR |= 0X1UL;
temp=RCC->AHBENR;//時(shí)鐘使能需2個(gè)周期
UNUSED(temp);//避免Warning
DMA1_Channel1->CPAR = (uint32_t)(ADC1_BASE+0X40);
DMA1_Channel1->CMAR = (uint32_t)(&dat_buf);
DMA1_Channel1->CNDTR = ADC_MAX * 2;
DMA1_Channel1->CCR |= (0X2UL<<12 | 0X1UL<<10 | 0X2UL<<8 | 0X1UL<<7 |
0X0UL<<3 | 0X1UL<<1 | 0X1 << 5);
//v-high priority, m-size=16,p-size=16,m-increase,
//error and complete interrupt, circular mode;
DMAMUX1_Channel0->CCR &= ~(0X7FUL);
DMAMUX1_Channel0->CCR |= (0X1FUL);//tim2 as request source
__NVIC_SetPriority(DMA1_Channel1_IRQn,0);
__NVIC_EnableIRQ(DMA1_Channel1_IRQn);
DMA1_Channel1->CCR |= 0X1UL;//enable DMA channel
return;
}
通過(guò)CR2的主模式位MMS[6:4]配置TIM2的Update為TRGO,否則無(wú)法正確觸發(fā)ADC;使能更新事件的DMA請(qǐng)求。 在上述框架下,DMA只要開啟單次模式,等待全傳輸中斷函數(shù)置標(biāo)志位就可以了。需要注意的是,在清除中斷標(biāo)志的時(shí)候,需要同時(shí)清除NVIC端和外設(shè)端的標(biāo)志位,否則會(huì)陷入無(wú)限的中斷循環(huán)。 若開啟了上述外設(shè)配置,則上述架構(gòu)在DMA One shot模式下就能完成采樣率可調(diào)的循環(huán)數(shù)據(jù)傳輸。而我們最終開啟的是DMA Circular模式,這將在后面說(shuō)明。2. 觸發(fā)電平的實(shí)現(xiàn),以及負(fù)時(shí)間的實(shí)現(xiàn)觸發(fā)電平,即以被測(cè)信號(hào)越過(guò)某個(gè)閾值電壓為起算點(diǎn),采集后面的若干個(gè)數(shù)據(jù)。該方法可以使波形穩(wěn)定地顯示在屏幕上。 負(fù)時(shí)間,即可以顯示觸發(fā)電平前一定時(shí)間內(nèi)的波形。當(dāng)觸發(fā)電平用于異常信號(hào)的單次捕捉(Single模式)時(shí),負(fù)時(shí)間可以顯示異常信號(hào)前的波形。 有同學(xué)在無(wú)條件采樣后計(jì)算一組數(shù)據(jù)的均值(中值),并顯示從中值樣點(diǎn)開始的數(shù)據(jù),從而通過(guò)軟件實(shí)現(xiàn)觸發(fā)電平。這種方案在實(shí)現(xiàn)AUTO時(shí)不失為一個(gè)好的啟發(fā),但在此面臨兩個(gè)問(wèn)題:第一,單純的中值判斷無(wú)法控制觸發(fā)的極性,即無(wú)法選擇上升沿還是下降沿觸發(fā)。若增加前后值判斷,則將增加軟件運(yùn)算量;第二,這種算法下不可能出現(xiàn)“無(wú)觸發(fā)”的、波形亂晃的現(xiàn)象,與真實(shí)的數(shù)字示波器存在差異。從本質(zhì)上講,這種方法沒有充分利用硬件底層。 G031的ADC自帶一個(gè)模擬看門狗,即Analog Window Watchdog的特性。即當(dāng)采樣值超出規(guī)定范圍(窗口)時(shí),輸出AWD_OUT將持續(xù)拉高,直至電壓落回窗口內(nèi),延遲為一個(gè)轉(zhuǎn)換周期。void TIM2_Init(unsigned int priority)
{
uint32_t temp;
RCC->APBENR1 |= 0X1UL;//使能TIM2時(shí)鐘
temp=RCC->APBENR1;
UNUSED(temp);
//TIM2->DIER |= 0X1UL;//允許更新中斷
TIM2->CR1 |= 0X1UL<<2UL;//手動(dòng)更新不觸發(fā)中斷
TIM2->CR2 |= 0X2<<4;//update as TRGO
TIM2->SMCR |= 0X1UL<<7;
TIM2->DIER |= 0X1UL<<8;
TIM2->ARR = 16-1;
TIM2->PSC = 0;
temp=TIM2->ARR;
TIM2->EGR |= 0X1UL;//手動(dòng)更新寄存器值
temp=TIM2->PSC;
UNUSED(temp);
}
![c25b692e-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9viARCM-AAC7BATsETk911.jpg)
![c2702634-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9viAXrS_AABuO1DQ550296.jpg)
![c27f7a12-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9viAUxY5AAB56rGE1M0217.jpg)
![c2993eb6-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9viADit2AABPK8hJRU8015.jpg)
![c2acb96e-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9viAQhxLAACQYf1MfeI303.jpg)
3. 信號(hào)頻率的測(cè)定數(shù)字測(cè)定頻率的方法,一般是先整形再測(cè)量。即通過(guò)施密特觸發(fā)器(比如TLV3501)先把信號(hào)整形成脈沖,再對(duì)脈沖進(jìn)行測(cè)定。對(duì)脈沖的測(cè)定也有兩種思路:一是直接同步采樣后計(jì)算脈沖個(gè)數(shù),適用于較高頻率;二是計(jì)算脈沖高低電平的周期個(gè)數(shù),適用于較低頻率。兩種方法均受限于系統(tǒng)最高主頻。這也是本項(xiàng)目至今為止兩個(gè)尚為得出最優(yōu)解的難點(diǎn)之一。 本項(xiàng)目從脈沖整形到計(jì)數(shù)均采用硬件特性為主、軟件程序?yàn)檩o的思路。根據(jù)前面的討論可知,ADC的AWD在一定頻率以下等效于一個(gè)極其理想的脈沖整形器。相較于模擬施密特觸發(fā)器,其最大的特點(diǎn)在于脈沖整形的響應(yīng)特性與信號(hào)峰峰值的絕對(duì)值無(wú)關(guān),而僅受到信道噪聲和量化噪聲的干擾。因此,測(cè)量頻率最基本的方法,也是本項(xiàng)目采用的方法,就是對(duì)AWD的輸出信號(hào)AWD_OUT在一定時(shí)間內(nèi)進(jìn)行計(jì)數(shù)。此方法實(shí)現(xiàn)起來(lái)最為簡(jiǎn)單,但面臨兩個(gè)很大的問(wèn)題:第一,相比于FPGA廣泛采用的雙閘門法,此方法會(huì)把閘門時(shí)間的前后沿漏掉,引入一定的誤差,但這并非主要矛盾。if((!(cursor_buf & (0X1 << 7))) || ((cursor_buf & (0X1 << 7)) && (single_flag == 0)))
{
TIM1->ARR = TIM2->ARR;
TIM1->PSC = (TIM2->PSC + 1) * 256 - 1;
TIM1->EGR |= 0X1;
{
DMA1_Channel1->CNDTR = ADC_MAX * 2;
DMA1_Channel1->CCR |= 0X1UL;
TIM1->SR &= ~(0X1UL);
TIM2->CR1 |= 0X1UL;
}
while(!(dat_buf_ready & 0X01))
{
}
TIM1->DIER |= (0X1UL);
TIM1->SMCR |= (0X0UL<<16 | 0X6UL);
dat_buf_ready &= ~(0X1);
}
void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
CH1_CNDTR = DMA1_Channel1->CNDTR;//賦值了不一定用,但這樣最準(zhǔn)確
if(TIM1->SR & 0X1UL)
{
{
TIM2->CR1 &= ~(0X1UL);
TIM1->CR1 &= ~(0X1UL);
//Stop tim2 and consequently stop DMA
TIM2->CNT = 0;//resetting TIM2
dat_buf_ready |= 0X1 << 7;//setting complement flag
}
TIM1->SR &= ~(0X1UL);
__NVIC_ClearPendingIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
}
}
void DMA1_Channel1_IRQHandler(void)//中斷服務(wù)函數(shù)
{
DMA1->IFCR |=0X1UL;
dat_buf_ready |= 0X1;
__NVIC_ClearPendingIRQ(DMA1_Channel1_IRQn);
}
![c2be980a-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9viAOelOAABkcQQB50g293.jpg)
4. 如何計(jì)算信號(hào)頻譜本項(xiàng)目的FFT算法沒有調(diào)用任何除C++標(biāo)準(zhǔn)庫(kù)以外的庫(kù),這一方面是考慮到RAM空間的緊張,另一方面則是起到鍛煉的作用。 本項(xiàng)目的FFT算法就是最簡(jiǎn)單的256點(diǎn)基-2 FFT算法,將復(fù)數(shù)乘法拆分為實(shí)虛部進(jìn)行同址運(yùn)算,并將FFT因子存儲(chǔ)為const型常量。if((!(cursor_buf & (0X1 << 7))) || ((cursor_buf & (0X1 << 7)) && (single_flag == 0)))
//測(cè)量頻率
{
//配置參數(shù)
//保存TIM2原參數(shù),并設(shè)為2MHz采樣率
arr = TIM2->ARR;
TIM2->ARR = 16 - 1;
smp = (ADC1->SMPR) & 0X7;
ADC1->SMPR &= ~(0X7);
ADC1->SMPR |= 0X1;
psc = TIM2->PSC;
TIM2->PSC = 0;
//將TIM1的從模式更改為External Clock 1
//并打開數(shù)字濾波
TIM1->SMCR &= ~((0X1 << 16) | 0X7);
TIM1->SMCR |= 0X7;
TIM1->SMCR |= 0XF << 8;
TIM1->PSC = 0;
TIM1->ARR = 65535;
TIM1->CNT = 0;
TIM1->EGR |= 0X1;
//配置SysTick
SysTick->VAL = 0;
SysTick->LOAD = 16000000 -1;
//開啟測(cè)量
TIM2->CR1 |= 0X1;
TIM1->CR1 |= 0X1;
SysTick->CTRL |= 0X1;
while(!(SysTick_UE_FLAG & 0X1))
{
}
//結(jié)束測(cè)量,恢復(fù)TIM1參數(shù)
TIM1->CR1 &= ~(0X1);
TIM2->CR1 &= ~(0X1);
SysTick_UE_FLAG &= ~(0X1);
TIM1->SMCR &= ~((0X1 << 16) | 0X7);
TIM1->SMCR &= ~(0XF << 8);
}
![c2d8a5d8-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9vmASF1NAACp1sP_Mas198.jpg)
![c303b1c4-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9vmATBEXAAIy5zxbXo4182.jpg)
這樣做的顯著好處就是極大地節(jié)省了RAM空間。因?yàn)樽钚〉淖兞恳彩?位,卻沒有任何參數(shù)達(dá)到256檔之多,尤其是那些只有一位的標(biāo)志位,完全沒有必要用8位變量表示。當(dāng)然,這又是一對(duì)用時(shí)間換空間的矛盾。因?yàn)槲贿\(yùn)算的操作量是直接賦值運(yùn)算的3倍,這是在內(nèi)存空間緊張的情況下最好的選擇。5. 如何以盡可能低的誤判率獲取按鍵和旋鈕的信息由硬件電路可知,旋鈕的AB相、旋鈕按鍵、左右按鍵,分別連接在PB4,PA15,PB3,PA4,PA5上。其中,三個(gè)按鍵只要用外部中斷+延時(shí)消抖就能很好地判斷,而旋鈕則具有一定的復(fù)雜性。//macros for register ui_buf
![c314191a-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9vmAAhVHAACmyd6sqDg596.jpg)
6. 如何以盡可能簡(jiǎn)潔的方式實(shí)現(xiàn)按鍵對(duì)GUI的改變由上述討論可以看出,最簡(jiǎn)潔的方式就是在每次進(jìn)入主循環(huán)后的固定位置,根據(jù)6個(gè)全局寄存器的值,共同決定本次循環(huán)應(yīng)該在屏幕上顯示什么,并清除所有的標(biāo)志位。由于實(shí)現(xiàn)該功能的UI_Refresh函數(shù)太長(zhǎng),這里僅以一個(gè)switch-case分支作為示例。void EXTI4_15_IRQHandler(void)
{
if(EXTI->FPR1 & (0X1 << 15))
{
flag |= 0X1 << 7;
if(!(GPIOB->IDR & (0X1 << 4)))
{
add_buf ++;
min_buf = 0;
}
else
{
min_buf ++;
add_buf = 0;
}
TIM17_Delay(5000-1,320-1);
EXTI->FPR1 |= 0X1 << 15;
}
if(EXTI->FPR1 & (0X1 << 4))//left key down,--, or switch to main ui
{
TIM17_Delay(5000-1,320-1);
if(!(GPIOA->IDR & (0X1 << 4)))
{
flag |= 0X1;
if(GPIOB->IDR & (0X1 << 3))//PB3 not down
{
if(!(M_S_FLAG & cursor_buf))//main ui
{
if(!(ui_buf & FFT_ON_BIT))
{
if((cursor_buf & M_UI_BITS) > 0)
cursor_buf -= 0X1 << M_UI_BITS_OFFSET;
}
else
{
fft_col |= 0X1 << 7;//變量標(biāo)志位
}
}
else//sub ui
{
if((cursor_buf & S_UI_BITS) > 0)
cursor_buf -= 0X1 << S_UI_BITS_OFFSET;
}
}
else//PB3 down
{
cursor_buf &= ~(M_S_FLAG);
}
}
EXTI->FPR1 |= 0X1 << 4;
}
if(EXTI->FPR1 & (0X1 << 5))//right key down,++, or switch to sub ui
{
TIM17_Delay(5000-1,320-1);
if(!(GPIOA->IDR & (0X1 << 5)))
{
flag |= 0X1;
if(GPIOB->IDR & (0X1 << 3))//PB3 not down
{
if(!(M_S_FLAG & cursor_buf))//main ui
{
if(!(ui_buf & FFT_ON_BIT))
{
if((cursor_buf & M_UI_BITS) < (0X4 << M_UI_BITS_OFFSET))
cursor_buf += 0X1 << M_UI_BITS_OFFSET;
}
else
{
fft_col &= ~(0X1 << 7);
}
}
else//sub ui
{
if((cursor_buf & S_UI_BITS) < (0X4 << S_UI_BITS_OFFSET))
cursor_buf += 0X1 << S_UI_BITS_OFFSET;
}
}
else//PB3 down
{
cursor_buf |= M_S_FLAG;
}
}
EXTI->FPR1 |= 0X1 << 5;
}
__NVIC_ClearPendingIRQ(EXTI4_15_IRQn);
}
目至今沒有完全得出優(yōu)化解的另一個(gè)難點(diǎn)。雖然這樣的結(jié)構(gòu)很簡(jiǎn)潔,但我們后續(xù)就將看到:這種完全“同步”于主循環(huán),而屏蔽任何“異步”帶來(lái)的后果,就是當(dāng)水平時(shí)基很大時(shí),整個(gè)程序也會(huì)變得非常緩慢,以至于幾乎進(jìn)入了一種“假死”狀態(tài)。因?yàn)榧词拱聪铝税存I,至少也要等一次主循環(huán)結(jié)束。而在以低的采樣率采集數(shù)十Hz信號(hào)時(shí),連同等待觸發(fā)加256個(gè)采樣點(diǎn)在內(nèi)的時(shí)間,是相當(dāng)可觀的。這啟示我們,中斷服務(wù)函數(shù)應(yīng)該真的具有“中斷”的作用,而不僅僅是完成一個(gè)硬件電路就可以實(shí)現(xiàn)的狀態(tài)機(jī)。至于采樣處理模塊的更新,則與GUI的更新如出一轍:同樣是根據(jù)6個(gè)全局寄存器的值來(lái)更新,這樣保證了顯示與實(shí)際相符。只不過(guò)這一次更新的是模擬開關(guān)檔位、TIM2溢出頻率,TIM14與TIM16的PWM波占空比等參數(shù)。case (0X1 << M_UI_BITS_OFFSET)://水平分格
{
flag |= 0X1 << 2;
&& ((ui_buf & TIME_BASE_BITS) < (0XF << TIME_BASE_BITS_OFFSET)))
{
add_buf = 0;
ui_buf += (0X1 << TIME_BASE_BITS_OFFSET);
}
else if(min_buf && ((ui_buf & TIME_BASE_BITS) > (0X1 << TIME_BASE_BITS_OFFSET)))
{
min_buf = 0;
ui_buf -= (0X1 << TIME_BASE_BITS_OFFSET);
}
break;
}
事實(shí)上,這是本項(xiàng)
其他功能簡(jiǎn)述?
在核心部分以外,以下將對(duì)AUTO,Single以及波形顯示函數(shù)作簡(jiǎn)要的論述。 1. AUTO功能所謂的AUTO功能,是指示波器根據(jù)當(dāng)前被采信號(hào)的直流偏置、峰峰值、頻率等特點(diǎn),自動(dòng)調(diào)節(jié)顯示時(shí)基、觸發(fā)電平、垂直尺度等參數(shù),使得整個(gè)波形盡可能以最大的完整度和占滿率顯示在屏幕上。 在本程序中,頻率的測(cè)定與采樣時(shí)基無(wú)關(guān),這對(duì)AUTO的實(shí)現(xiàn)無(wú)疑是有利的。而由于輸入端采用了反相放大(衰減)器加同相端直流偏置的方式,而不是在同一端接成加法器,因此直流偏置的概念本身變得模糊。![c3296554-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9vmAR1dhAABeZiKcIpo202.jpg)
![c33a5a08-a917-11ec-952b-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/94/A8/wKgaomTl9vmAROR6AAD4SM9qpXk791.jpg)
總結(jié)與思考?
由于此前完全沒有獨(dú)立進(jìn)行過(guò)這種完整項(xiàng)目的開發(fā),更沒有試過(guò)完全擺脫庫(kù)函數(shù)的束縛,直接對(duì)著器件手冊(cè)進(jìn)行寄存器編程,因此從這個(gè)意義上講,這次項(xiàng)目實(shí)踐的收獲無(wú)疑是豐碩的。 寄存器編程的巨大好處不僅僅在于證明自己有不再跟著別人編寫的庫(kù)函數(shù)亦步亦趨的能力,而更多地在于對(duì)單片機(jī)的硬件特性本身有了更加深入和透徹的理解。單是覺得看懂了器件手冊(cè)卻不會(huì)根據(jù)自己對(duì)它的理解進(jìn)行編程,抑或單是學(xué)會(huì)用庫(kù)函數(shù)拼湊出各種功能而不知其所以然,在我看來(lái)都不是學(xué)習(xí)嵌入式最終的目的。換句話說(shuō),我既不想像“嵌入式接口技術(shù)”課那樣,花一個(gè)學(xué)期背完一份考綱,也不想把嵌入式開發(fā)玩成一個(gè)純軟件的東西。 這其中當(dāng)然也摻雜著很大的個(gè)人因素。在參加電賽的一年半里,我已經(jīng)受夠了在那些被奉為神諭的庫(kù)函數(shù)面前不得不唯唯諾諾的姿態(tài),為此我還我曾經(jīng)干出過(guò)這樣的蠢事:每次新建一個(gè)工程,就把所有相關(guān)的外設(shè)驅(qū)動(dòng)庫(kù)函數(shù)復(fù)制一份過(guò)去,以至于銳減的E盤容量呈現(xiàn)出一派日積月累和勤學(xué)苦練的虛假繁榮——全都是泡沫經(jīng)濟(jì)罷了。 性格執(zhí)拗與固執(zhí)行事,就好比在眾目睽睽之下丟開大路不走,而非要在泥潭水溝里摔得鼻青臉腫,比的就是在他人的冷嘲熱諷與自己的自我懷疑中,哪個(gè)會(huì)先讓你破防。別人看了視頻,用一行代碼一分鐘就點(diǎn)亮的燈,我卻花了半天還差點(diǎn)沒累死在電腦前,換來(lái)的是兩個(gè)刻骨銘心的知識(shí)點(diǎn):配置外設(shè)前要先打開RCC的時(shí)鐘位,以及GPIO MODER的復(fù)位值是全1而不是全0。當(dāng)綠燈亮起來(lái)的那一刻,我才深切地意識(shí)到,自己還有很長(zhǎng)的路需要走。 我的另一個(gè)教訓(xùn)在于低估了GUI設(shè)計(jì)的難度。在2月9號(hào)完成了核心部分的架構(gòu)之后,我天真地以為只要享受接下來(lái)的過(guò)程就好了,殊不知行百里者半九十,真正魔鬼的東西,恰恰還在后頭。時(shí)至今日,我雖然好歹結(jié)了個(gè)項(xiàng),但心中的滿足簡(jiǎn)直微乎其微。程序跑出來(lái)的整體結(jié)果很不理想,單純的實(shí)現(xiàn)功能與不惡心你的用戶之間,隔的真不是一兩條鴻溝。在敲完代碼后,我才意識(shí)到是否應(yīng)該引入一個(gè)簡(jiǎn)單的操作系統(tǒng)來(lái)實(shí)現(xiàn)一個(gè)更加人性化的GUI,因?yàn)榇鞌∈刮乙庾R(shí)到:這種“睜眼主循環(huán),閉眼進(jìn)中斷”的思維,可能確實(shí)有點(diǎn)太單細(xì)胞了。 除此之外,實(shí)現(xiàn)一個(gè)示波器所需的各種基本功能,我也有了一個(gè)大體的理解。知識(shí)決定想象力的范疇,這與我一貫的認(rèn)知相符——畢竟在此之前,我也只限于紙上談兵地構(gòu)建一款擁有各種功能示波器,卻每每止步于“這個(gè)功能理論上可以實(shí)現(xiàn)”。然而當(dāng)我試圖把自己的想法變?yōu)楝F(xiàn)實(shí),理論和實(shí)際的差距才會(huì)一次次地刷新我的認(rèn)知:別人說(shuō)起來(lái)輕描淡寫的東西,始終都只是別人的。 后續(xù)的改進(jìn)我不會(huì)在這個(gè)項(xiàng)目的基礎(chǔ)上完成,而會(huì)在一個(gè)去年遺留下來(lái)的產(chǎn)學(xué)合作項(xiàng)目中,轉(zhuǎn)移到F407和G031構(gòu)成的雙MCU結(jié)構(gòu)(我都沒臉說(shuō)“雙核系統(tǒng)”,真的)上完成。至于這個(gè)平臺(tái),它還有實(shí)驗(yàn)價(jià)值。我還得用它來(lái)搞清楚,為什么用外部時(shí)鐘驅(qū)動(dòng)計(jì)時(shí)器時(shí),溢出更新無(wú)法觸發(fā)DMA——這是我在本次寄存器編程中唯一一個(gè)尚未解釋清楚的問(wèn)題。審核編輯 :李倩
-
示波器
+關(guān)注
關(guān)注
113文章
6293瀏覽量
185958 -
STM32
+關(guān)注
關(guān)注
2273文章
10926瀏覽量
357821
原文標(biāo)題:如何使用STM32G031開發(fā)板實(shí)現(xiàn)雙通道示波器-2022年寒假在家練STM32平臺(tái)項(xiàng)目分享(一)
文章出處:【微信號(hào):xiaojiaoyafpga,微信公眾號(hào):電子森林】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
stm32G031串口外部不接上拉電阻,導(dǎo)致stm32進(jìn)入到了硬件中斷怎么解決?
為什么Stm32g031芯片無(wú)法進(jìn)入bootloader狀態(tài)呢
STM32G031無(wú)線溫濕度儀開源
使用STM32G031運(yùn)行CRC計(jì)算但結(jié)果不匹配是哪里出問(wèn)題了
是否可以將14.7456MHz晶體與STM32G031 (LQFP32) 一起使用?
基于FPGA的雙通道簡(jiǎn)易可存儲(chǔ)示波器設(shè)計(jì)
51開發(fā)板實(shí)現(xiàn)計(jì)算器
STM32F103ZET6開發(fā)板實(shí)現(xiàn)俄羅斯方塊小游戲
使用STM32開發(fā)板實(shí)現(xiàn)俄羅斯方塊游戲的工程文件和源代碼免費(fèi)下載
![使用<b class='flag-5'>STM32</b><b class='flag-5'>開發(fā)板實(shí)現(xiàn)</b>俄羅斯方塊游戲的工程文件和源代碼免費(fèi)下載](https://file.elecfans.com/web1/M00/AF/4D/o4YBAF3khHyAA7xRAAOnYb58J8Y489.png)
STM32實(shí)例——基于STM32開發(fā)板實(shí)現(xiàn)傳感數(shù)據(jù)采集-DHT11溫濕度采集
![<b class='flag-5'>STM32</b>實(shí)例——基于<b class='flag-5'>STM32</b><b class='flag-5'>開發(fā)板實(shí)現(xiàn)</b>傳感數(shù)據(jù)采集-DHT11溫濕度采集](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
基于STM32G031開發(fā)板的雙通道簡(jiǎn)易示波器設(shè)計(jì)
STM32G031J6開發(fā)板
![<b class='flag-5'>STM32G031</b>J6<b class='flag-5'>開發(fā)板</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評(píng)論