0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

如何使用TimeQuest

工程師 ? 來源:網(wǎng)絡整理 ? 作者:h1654155205.5246 ? 2019-03-08 14:52 ? 次閱讀

如何使用TimeQuest

Altera的話來說,TimeQuest Timing Analyzer是一個功能強大的,ASIC-style的時序分析工具。采用工業(yè)標準--SDC(synopsys design contraints)--的約束、分析和報告方法來驗證你的設計是否滿足時序設計的要求。

TimeQuest的基本操作流程

做為altera FPGA開發(fā)流程中的一個組成部分,TimeQuest執(zhí)行從驗證約束到時序仿真的所有工作。Altera推薦使用下面的流程來完成TimeQuest的操作。

1、建立項目并加入相關設計文件

不管做什么事情,都需要有一個目標或者說對象。我們用TimeQuest做時序分析,當然也需要一個對象,這個對象實際上就是我們的設計。所以首先是建立一個Quartus II的項目,并把所有需要的設計文件都加入到項目中去。需要注意的一點是,這里的設計文件,不僅僅包含邏輯設計相關的文件,也包含已經(jīng)存在的時序約束文件,當然,需要以synopsys Design Constraints(.sdc)的格式存在的。關于 sdc文件,可以使用Quartus的向?qū)斫?,在生成sdc文件后,你可以再在此sdc文件上進行自己的修改,如下圖所示,Assignments-》TimeQuest Timing Analyzer Wizard.。。

2、對項目進行預編譯(initial compilation)

項目建立以后,如果從來沒有對項目進行過編譯的話,就需要對項目進行預編譯。這里的預編譯是對應于全編譯(full compilation)來講的,我們可以理解為預編譯是對項目進行部分的編譯,而全編譯是對項目進行完整的編譯。做預編譯的目的是為了生成一個initial design database,然后我們可以根據(jù)這個database用Timequest采用交互的模式生成時序約束。實際上,對于小的設計,編譯時間并不是很長的話,完全可以不去區(qū)分預編譯和全編譯,需要編譯的時候,直接做全編譯就可以了,做全編譯的話,可以生成一個post-fit的database,完全可以給TimeQuest使用。

3、向設計中添加時序約束

在用TimeQuest做時序分析之前,必須要指定出對時序的要求,也就是我們通常所說的時序約束。這些約束包括時鐘,時序例外(timing exceptions)和輸入/輸出延時等。

默認情況下,Quartus II 軟件會給所有沒有被下約束的時鐘都設定為1GHz。沒有任何的時序例外,也就是說所有的timing path都按1T去check。所有的輸入/輸出的延遲都按0來計算。這顯然不符合絕大多數(shù)設計的時序要求,所以有必要根據(jù)設計的特性,添加必要的時序約束。

如上所述,時序約束主要包括三類:時鐘,時序例外和輸入/輸出延遲。其中時鐘和輸入/輸出延遲可以認為是在某種程度上增強時序設計的要求。而時序例外可以認為是在某種程度上降低時序設計的要求。比如說,僅僅設定一個時鐘的頻率為100MHz的話,這個時鐘域里所有timing path都需要能工作在100MHz下。這顯然是增強了時序設計的要求??墒侨绻谶@個時鐘域下面,有部分timing path是不需要做1T的check的,那么就可以通過添加時序例外來避免對這些timing path做1T的check,即降低了時序設計的要求。

在用TimeQuest做時序分析時,如果非常熟悉設計的構架和對時序的要求,又比較熟悉sdc的相關命令,那么可以直接在sdc文件里輸入時序約束的命令。而通常情況下,可以利用TimeQuest GUI提供的設定時序約束的向?qū)砑訒r序約束。不過要注意的是,用向?qū)傻臅r序約束,并不會被直接寫到sdc文件里,所以如果要保存這些時序約束,必須在TimeQuest用write sdc的命令來保存所生成的時序約束。

4. 執(zhí)行完整的編譯

在設定好時序約束以后,就需要對整個設計進行完整的編譯。在編譯過程中,軟件會優(yōu)化設計的邏輯、布局布線等來盡可能滿足所有的時序約束。

如果沒有添加時序約束,那么軟件在編譯的時候,會按照默認的時序約束對設計進行優(yōu)化,對于絕大多數(shù)的設計,都會報出來時序的問題,但因為默認的時序約束與設計本身的要求在絕大多數(shù)情況下,都是不同的,所以這些時序的問題也并不是設計本身的問題,并沒有太多的參考價值,而且很多初學者也不會注意到這個問題。這樣就把設計中很多潛在的時序問題給隱藏起來了,最終帶來的可能就是系統(tǒng)運行的不穩(wěn)定,甚至是完全不能運行。

5. 驗證時序

當完成編譯以后,我們就可以用TimeQuest來驗證時序了。在時序分析的過程中,TimeQuest會分析設計中所有的timing path,計算每一條timing path的延時,檢查每一條timing path是否滿足時序約束,最后按照positive slack或negative slack來報告時序分析的結(jié)果。其中negative slack就表示對應的timing path不滿足時序約束的要求(timing violation)。

如果遇到有不滿足時序要求的情況,則可以根據(jù)對應的時序報告分析設計,確定如何優(yōu)化設計使之滿足時序約束。時序約束有任何變化的話,都需要重新編譯設計。這個反復的過程可以讓我們解決設計中的時序問題。

DAC7512控制器

DAC7512是一個具有三線串行接口的DAC。我們基于FPGA用Verilog語言實現(xiàn)了一個簡單的DAC7512的控制器。下面是控制器的結(jié)構圖

DAC7512控制器由三個模塊組成,PLL用來生成控制器所要的時鐘C0(25MHz)和C1(50MHz),其lock信號用來做為控制器的異步reset。da_data模塊生成要送往DAC7512的數(shù)據(jù),其中DA_DATA為數(shù)據(jù),DA_DATA_EN為數(shù)據(jù)有效信號,該模塊使用C0時鐘,整個屬于C0時鐘域。DAC7512模塊用于將DA_DATA轉(zhuǎn)換成符合DAC7512接口標準的串行數(shù)據(jù)并送給DAC7512,要用到C1(50MHz)和DA_SCLK(C1二分頻,25MHz)兩個時鐘。

DAC7512控制器一共有四個輸入輸出端口。CLK_IN為PLL的基準時鐘,為25MHz。DA_DIN,DA_SCLK和DA_SYNC為三線串口,都為輸出端口。由于C0,C1是由同一個PLL輸出的,DA_SCLK是由C1經(jīng)二分頻得到的,三者之間是同步的,處于同一個clock group中。不過要注意一點的是,在串行總線上,DA_DIN是在DA_SCLK的下降沿有效的。把DA_DIN設計為C1時鐘域的信號,并控制其值只在DA_SCLK為高電平的時候發(fā)生變化。這樣可以把DA_DIN與DA_SCLK之間的時序要求轉(zhuǎn)換為DA_DIN在C1時鐘域的時序要求,具體的使用方法我們跟著視頻一起來學習一下。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • TimeQuest
    +關注

    關注

    0

    文章

    11

    瀏覽量

    11376
收藏 人收藏

    評論

    相關推薦

    MODBUS轉(zhuǎn)CCLINK IE FIELD BASIC網(wǎng)關模塊上位機和PLC通訊案例

    通過捷米JM-CCLKIE-TCP網(wǎng)關將網(wǎng)絡中的設備數(shù)據(jù)轉(zhuǎn)換為 Modbus-TCP 協(xié)議格式并傳輸?shù)狡髽I(yè)的各類管理系統(tǒng)中,企業(yè)能夠?qū)崿F(xiàn)對生產(chǎn)過程的實時監(jiān)控和精細化管理。
    的頭像 發(fā)表于 01-04 12:36 ?39次閱讀
    MODBUS轉(zhuǎn)CCLINK IE FIELD BASIC網(wǎng)關模塊上位機和PLC通訊案例

    航空插頭的力量之源:廠家的核心競爭力解碼

    在工業(yè)領域的深處,有一群默默無聞的守護者,它們是小巧卻關鍵的航空插頭。而這些航空插頭的背后,是那些廠家的智慧和力量。今天,讓我們揭開神秘的面紗,探尋航空插頭廠家的優(yōu)勢所在。
    的頭像 發(fā)表于 01-04 11:46 ?41次閱讀
    航空插頭的力量之源:廠家的核心競爭力解碼

    連接器:工廠中的生命線,默默無聞的紐帶

    在現(xiàn)代化的工廠中,機器的轟鳴聲、流水線的忙碌身影,構成了工業(yè)生產(chǎn)的交響樂。而在這龐大的體系中,有一個不起眼的元件,它的作用卻至關重要——這就是連接器。連接器,在工廠中,是一個極為重要的存在,它們?nèi)缤€一般,維系著整個生產(chǎn)流程的順暢與穩(wěn)定。
    的頭像 發(fā)表于 01-04 11:33 ?56次閱讀
    連接器:工廠中的生命線,默默無聞的紐帶

    CCLINK IE FIELD BASIC轉(zhuǎn)Modbus TCP三菱PLC和變頻器通訊案例

    捷米JM-CCLKIE-TCP網(wǎng)關可以分別從CCLINK IE FB一側(cè)和MODBUS一側(cè)讀寫數(shù)據(jù),然后將數(shù)據(jù)存入各自的緩沖區(qū)。接著,網(wǎng)關內(nèi)部會將緩沖區(qū)的數(shù)據(jù)進行交換,從而實現(xiàn)兩邊數(shù)據(jù)的傳輸。這樣的設計使得網(wǎng)關在處理不同協(xié)議的數(shù)據(jù)時更加靈活和高效。
    的頭像 發(fā)表于 01-04 11:27 ?89次閱讀
    CCLINK IE FIELD BASIC轉(zhuǎn)Modbus TCP三菱PLC和變頻器通訊案例

    中軟高科身份證讀取及M1卡讀寫二合一機具開發(fā)文檔

    中軟高科這款機具除了二代身份證閱讀功能,還可以對M1卡進行讀寫操作,從而實現(xiàn)身份證識讀與M1制卡二合一。 機具照片 開發(fā)文檔
    發(fā)表于 01-04 11:25

    【正點原子STM32H7R3開發(fā)套件試用體驗】【主貼】- 基于STM32H7R3的遠程隧道氣壓監(jiān)測終端

    基于STM32H7R3的遠程隧道氣壓監(jiān)測終端 前言 在當今的交通網(wǎng)絡中,隧道扮演著舉足輕重的角色,無論是公路、鐵路還是地鐵,隧道都極大地縮短了行程,提高了通行效率。然而,你是否知道,隧道內(nèi)的氣壓變化其實暗藏玄機,與我們的出行安全緊密相連。 當隧道內(nèi)外氣壓失衡時,可能會引發(fā)一系列問題。比如,氣壓差過大可能導致車輛耳鳴、頭暈,影響駕駛員的注意力和反應能力,給行車安全帶來隱患;對于隧道結(jié)構本身而言,長期異常的氣壓波動還可能加速墻壁、襯砌的老化與損壞。此外,在一些特殊情況下,如火災、爆炸事故發(fā)生時,氣壓的急劇變化更是關乎人員能否安全疏散。 為了精準掌控隧道內(nèi)的氣壓狀況,基于 STM32H7R3 的遠程隧道氣壓監(jiān)測終端應運而生。這款監(jiān)測終端如同一位忠誠的 “氣壓衛(wèi)士”,時刻堅守崗位,為隧道安全保駕護航。 硬件設計框圖 整個設計以正點原子的開發(fā)板作為原型設計模板,主控為STM32H7R3,配合BMP388 氣壓傳感器檢測隧道內(nèi)部的氣壓、六軸傳感器8658A完成隧道形變監(jiān)測,完成主要的隧道安全情況的檢測。 主控STM32H7R3是 STM32H7 系列中的高性價比子系列,內(nèi)置高性能 Cortex-M7 內(nèi)核,主頻高達 600MHz,這就好比給終端配備了一臺超強動力的引擎,使其擁有閃電般的運算速度,能夠快速處理各類復雜的數(shù)據(jù)。 與傳統(tǒng)芯片相比,STM32H7R3 在數(shù)據(jù)處理能力上有著質(zhì)的飛躍。以常見的 STM32F103 系列為例,其主頻大多在 72MHz 左右,而 STM32H7R3 的 600MHz 主頻意味著它每秒能夠執(zhí)行的指令數(shù)遠超前者,在處理大量氣壓數(shù)據(jù)時更加得心應手,幾乎不會出現(xiàn)卡頓現(xiàn)象,確保了監(jiān)測的實時性。 不僅如此,STM32H7R3 還具備強大的存儲能力。它集成了大容量的內(nèi)部 SRAM 存儲器,同時擁有高速的外部存儲接口,無論是運行程序所需的空間,還是存儲采集到的氣壓數(shù)據(jù),都能輕松應對。這就好比給你一個超大的倉庫,你可以隨心所欲地存放各種物品,不用擔心空間不足。在面對隧道氣壓監(jiān)測這種需要長時間、不間斷采集和存儲數(shù)據(jù)的任務時,強大的存儲能力尤為重要,它能夠記錄下氣壓的每一個細微變化,為后續(xù)的分析提供充足的數(shù)據(jù)支持。 在這款基于 STM32H7R3 的監(jiān)測終端中,選用的是高精度、高穩(wěn)定性的氣壓傳感器。它具備諸多優(yōu)勢,例如其精度可達 ±0.01hPa,相較于普通精度為 ±0.1hPa 的傳感器,能夠捕捉到更為細微的氣壓波動,就如同用高倍顯微鏡去觀察物體,不放過任何一個細節(jié)。而且,它的穩(wěn)定性極佳,在長時間、復雜的隧道環(huán)境下,依然能夠穩(wěn)定輸出準確的數(shù)據(jù),不會因為溫度、濕度的變化或者輕微的震動而出現(xiàn)較大偏差。這得益于其先進的溫度補償算法,能夠自動抵消環(huán)境溫度對氣壓測量的影響,確保數(shù)據(jù)的可靠性。 為了讓氣壓傳感器始終保持最佳狀態(tài),定期的校準與維護必不可少。一般來說,每隔一段時間(如一個月),就需要使用標準氣壓源對傳感器進行校準,檢查其測量值與標準值之間的偏差,若偏差超出允許范圍,則通過特定的校準程序?qū)鞲衅鬟M行調(diào)整。同時,還要注意傳感器的防護,避免灰塵、水汽等雜質(zhì)進入傳感器內(nèi)部影響其性能, 軟件處理流程 在軟件處理流程長,我們采取了分時處理的方式,隔一段時間采集氣壓以及姿態(tài)數(shù)據(jù),并對數(shù)據(jù)進行粗略的處理,保證數(shù)據(jù)的穩(wěn)定性。 整體的處理流程如上圖所示,按照順序完成氣壓、姿態(tài)傳感器的處理,以及報警狀態(tài)的上送 實物測試 整體的硬件連接如圖,外接BMP388傳感器模塊,配合開發(fā)板上的姿態(tài)傳感器一起作為此次的終端傳感器。 整體的數(shù)據(jù)顯示如上圖。 在測試過程中的數(shù)據(jù)調(diào)試波形測試。 代碼展示 ` int main(void) { uint8_t t = 0; uint8_t key; uint8_t report = 0; float temperature; float gyro[3]; float accel[3]; float euler_angle[3] = {0, 0, 0}; sys_mpu_config(); /* 配置MPU */ sys_cache_enable();/* 使能Cache */ HAL_Init(); /* 初始化HAL庫 */ sys_stm32_clock_init(300, 6, 2); /* 配置時鐘,600MHz */ delay_init(600);/* 初始化延時 */ usart_init(500000);/* 初始化串口 */ led_init(); /* 初始化LED */ key_init(); /* 初始化按鍵 */ pressSensorInit(&enPressureType); hyperram_init();/* 初始化HyperRAM */ lcd_init(); /* 初始化LCD */ lcd_show_string(30, 50, 200, 16, 16, \"STM32\", RED); lcd_show_string(30, 70, 200, 16, 16, \"QMI8658A TEST\", RED); lcd_show_string(30, 90, 200, 16, 16, \"ATOM@ALIENTEK\", RED); lcd_show_string(30, 110, 200, 16, 16, \"KEY0:UPLOAD ON/OFF\", RED); while (qmi8658_init() != 0)/* 初始化QMI8658A */ { lcd_show_string(30, 130, 200, 16, 16, \"QMI8658A Error!\", RED); delay_ms(500); lcd_show_string(30, 130, 200, 16, 16, \"Please Check!\", RED); delay_ms(500); LED0_TOGGLE(); } lcd_show_string(30, 130, 200, 16, 16, \"QMI8658A Ready!\", RED); lcd_show_string(30, 150, 200, 16, 16, \"UPLOAD OFF\", BLUE); lcd_show_string(30, 170, 200, 16, 16, \"Temp : . C\", BLUE); lcd_show_string(30, 190, 200, 16, 16, \"Pitch: . C\", BLUE); lcd_show_string(30, 210, 200, 16, 16, \"Roll : . C\", BLUE); lcd_show_string(30, 230, 200, 16, 16, \"Yaw: . C\", BLUE); lcd_show_string(30, 260, 200, 16, 16, \"BMP388 TEST\", RED); lcd_show_string(30, 280, 200, 16, 16, \"Press:Pa \", BLUE); lcd_show_string(30, 300, 200, 16, 16, \"Alti :cm \", BLUE); while (1) { qmi8658_read_xyz(accel, gyro); pressSensorDataGet(&s32TemperatureVal, &s32PressureVal, &s32AltitudeVal); key = key_scan(0); if (key == KEY0_PRES) { /* 切換匿名數(shù)據(jù)上報開關 */ report = !report; if (report == 0) { lcd_show_string(30, 150, 200, 16, 16, \"UPLOAD OFF\", BLUE); } else { lcd_show_string(30, 150, 200, 16, 16, \"UPLOAD ON \", BLUE); } } /* 獲取并顯示溫度 */ show_data(30, 170, qmi8658_get_temperature()); /* 獲取并顯示歐拉角 */ if (g_imu_init) { imu_get_eulerian_angles(accel, gyro, euler_angle, IMU_DELTA_T); show_data(30, 190, euler_angle[0]); show_data(30, 210, euler_angle[1]); show_data(30, 230, euler_angle[2]); lcd_show_num(80, 280,s32PressureVal ,9,16, BLUE); lcd_show_num(80, 300, s32AltitudeVal,9,16, BLUE ); if (report != 0) { /* 上報匿名狀態(tài)幀 */ qmi8658_send_data(accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);/* 發(fā)送加速度+陀螺儀原始數(shù)據(jù) */ usart1_report_imu((int)(euler_angle[1] * 100), (int)(euler_angle[0] * 100), (int)(euler_angle[2] * 100), 0, 0, 0); /* Pitch和Roll角位置調(diào)換 */ } } LED0_TOGGLE(); delay_ms(200); } } ` 整體的主函數(shù)如上圖,后期我將把所有的源碼通過附件上傳 `/** @file BMP388.cpp @authorWaveshare Team @version V1.0 @date Dec-2018 @BriefT @attention THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, WAVESHARE SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. ? COPYRIGHT 2018 Waveshare */ #include \"DRV_BMP388.h\" ////初始化IIC void BMP388_IIC_Init(void) { ////----------- //LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB); //LL_GPIO_SetPinMode(BMP388_SDA_Port,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_MODE_OUTPUT); //LL_GPIO_SetPinOutputType(GPIOB,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_OUTPUT_PUSHPULL);//推挽輸出 //LL_GPIO_SetPinSpeed(GPIOB,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_SPEED_FREQ_VERY_HIGH);//IO口速度 //LL_GPIO_SetPinPull(GPIOB,BMP388_SDA_Pin |BMP388_SCL_Pin,LL_GPIO_PULL_UP); ////--PB10,PB11 輸出高-- ////--PB10:SCLPB11:SDA //LL_GPIO_SetOutputPin(BMP388_SDA_Port,BMP388_SDA_Pin); //LL_GPIO_SetOutputPin(BMP388_SCL_Port,BMP388_SCL_Pin); ////--地址腳-- // LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB); //LL_GPIO_SetPinMode(GPIOB,LL_GPIO_PIN_12,LL_GPIO_MODE_OUTPUT); //LL_GPIO_SetPinOutputType(GPIOB,LL_GPIO_PIN_12,LL_GPIO_OUTPUT_PUSHPULL);//推挽輸出 //LL_GPIO_SetPinSpeed(GPIOB,LL_GPIO_PIN_12,LL_GPIO_SPEED_FREQ_VERY_HIGH);//IO口速度 //LL_GPIO_SetPinPull(GPIOB,LL_GPIO_PIN_12,LL_GPIO_PULL_UP); // //--地址引腳,設置地址為0x76-- //LL_GPIO_ResetOutputPin(GPIOB,LL_GPIO_PIN_12); GPIO_InitTypeDef gpio_init_struct = {0}; __HAL_RCC_GPIOE_CLK_ENABLE(); /* 配置LED0控制引腳 */ gpio_init_struct.Pin = BMP388_SDA_Pin; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(BMP388_SDA_Port, &gpio_init_struct); /* 配置LED0控制引腳 */ gpio_init_struct.Pin = BMP388_SCL_Pin; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(BMP388_SCL_Port, &gpio_init_struct); } //--設置SDA為輸出方向 void BMP388_SDA_OUT(void) { GPIO_InitTypeDef gpio_init_struct = {0}; gpio_init_struct.Pin = BMP388_SDA_Pin; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(BMP388_SDA_Port, &gpio_init_struct); BMP388_IIC_Delay(1); } //--設置SDA為輸入方向 void BMP388_SDA_IN(void) { GPIO_InitTypeDef gpio_init_struct = {0}; gpio_init_struct.Pin = BMP388_SDA_Pin; gpio_init_struct.Mode = GPIO_MODE_INPUT; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(BMP388_SDA_Port, &gpio_init_struct); BMP388_IIC_Delay(1); } //產(chǎn)生IIC起始信號 void BMP388_IIC_Start(void) { BMP388_SDA_OUT();//sda線輸出 BMP388_IIC_SDA_H ; BMP388_IIC_SCL_H; BMP388_IIC_Delay(1); BMP388_IIC_SDA_L;//START:when CLK is high,DATA change form high to low BMP388_IIC_Delay(1); BMP388_IIC_SCL_L;//鉗住I2C總線,準備發(fā)送或接收數(shù)據(jù) BMP388_IIC_Delay(1); } //產(chǎn)生IIC停止信號 void BMP388_IIC_Stop(void) { BMP388_SDA_OUT();//sda線輸出 BMP388_IIC_SCL_L; BMP388_IIC_SDA_L;//STOP:when CLK is high DATA change form low to high BMP388_IIC_Delay(1); BMP388_IIC_SCL_H; BMP388_IIC_Delay(1); BMP388_IIC_SDA_H ;//發(fā)送I2C總線結(jié)束信號 BMP388_IIC_Delay(1); } //等待應答信號到來 //返回值:1,接收應答失敗 //0,接收應答成功 unsigned char BMP388_IIC_Wait_Ack(void) { unsigned char ucErrTime=0; BMP388_SDA_IN();//SDA設置為輸入 BMP388_IIC_SDA_H ;BMP388_IIC_Delay(1); BMP388_IIC_SCL_H;BMP388_IIC_Delay(1); while(BMP388_READ_SDA) { ucErrTime++; if(ucErrTime>250) { BMP388_IIC_Stop(); return 1; } } BMP388_IIC_SCL_L;//時鐘輸出0 return 0; } //產(chǎn)生ACK應答 void BMP388_IIC_Ack(void) { BMP388_IIC_SCL_L; BMP388_SDA_OUT(); BMP388_IIC_SDA_L; BMP388_IIC_Delay(1); BMP388_IIC_SCL_H; BMP388_IIC_Delay(1); BMP388_IIC_SCL_L; } //不產(chǎn)生ACK應答 void BMP388_IIC_NAck(void) { BMP388_IIC_SCL_L; BMP388_SDA_OUT(); BMP388_IIC_SDA_H ; BMP388_IIC_Delay(1); BMP388_IIC_SCL_H; BMP388_IIC_Delay(1); BMP388_IIC_SCL_L; } //IIC發(fā)送一個字節(jié) //返回從機有無應答 //1,有應答 //0,無應答 void BMP388_IIC_Send_Byte(unsigned char txd) { unsigned char t; BMP388_SDA_OUT(); BMP388_IIC_SCL_L;//拉低時鐘開始數(shù)據(jù)傳輸 for(t=0;t<8;t++) { //--BMP388_IIC_SDA=(txd&0x80)>>7; if(((txd&0x80)>>7)==0x01) BMP388_IIC_SDA_H; else BMP388_IIC_SDA_L; txd<<=1; BMP388_IIC_SCL_H; BMP388_IIC_Delay(1); BMP388_IIC_SCL_L; BMP388_IIC_Delay(1); } } //讀1個字節(jié),ack=1時,發(fā)送ACK,ack=0,發(fā)送nACK unsigned char BMP388_IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; BMP388_SDA_IN();//SDA設置為輸入 for(i=0;i<8;i++ ) { BMP388_IIC_SCL_L; BMP388_IIC_Delay(1); BMP388_IIC_SCL_H; receive<<=1; if(BMP388_READ_SDA) receive++; BMP388_IIC_Delay(1); } if (!ack) BMP388_IIC_NAck();//發(fā)送nACK else BMP388_IIC_Ack(); //發(fā)送ACK return receive; } //--以上是驅(qū)動代碼,需要做更改--- static BMP388_ST_AVG gsstBMP388AvgFilter[3]; static BMP388_ST_CALI gsstCali; static unsigned char bmp388Check(void); static uint8_t bmp388Init(void); static void bmp388DataGet(int32_t* ps32Temp, int32_t* ps32Press, int32_t*ps32Alti); static void bmp388GetCalibrationData(void); static int64_t bmp388CompensateTemp(uint32_t u32RegData); static int64_t bmp388CompensatePress(uint32_t u32RegData); static void bmp388CalAvgValue(uint8_t *pu8Index, int32_t *ps32AvgBuffer, int32_t s32InVal, int32_t *ps32OutVal); uint8_t I2C_ReadOneByte(uint8_t DevAddr, uint8_t RegAddr) { uint8_t u8Ret; BMP388_IIC_Start(); BMP388_IIC_Send_Byte(DevAddr|0);//--寫地址-- BMP388_IIC_Wait_Ack(); BMP388_IIC_Send_Byte(RegAddr); BMP388_IIC_Wait_Ack(); BMP388_IIC_Start(); BMP388_IIC_Send_Byte(DevAddr|1);//--寫地址-- BMP388_IIC_Wait_Ack(); u8Ret=BMP388_IIC_Read_Byte(0); return u8Ret; } void I2C_WriteOneByte(uint8_t DevAddr, uint8_t RegAddr, uint8_t value) { BMP388_IIC_Start(); BMP388_IIC_Send_Byte(DevAddr|0);//發(fā)送器件地址+寫命令 if(BMP388_IIC_Wait_Ack())//等待應答 { BMP388_IIC_Stop(); return ; } BMP388_IIC_Send_Byte(RegAddr);//寫寄存器地址 BMP388_IIC_Wait_Ack();//等待應答 BMP388_IIC_Send_Byte(value);//發(fā)送數(shù)據(jù) if(BMP388_IIC_Wait_Ack())//等待ACK { BMP388_IIC_Stop(); return ; } BMP388_IIC_Stop(); return; } /****************************************************************************** pressure sensor module* ******************************************************************************/ void BMP388_IIC_Delay(uint32_t u32Count) { volatile uint32_t i; while(u32Count --) for(i = 0;i < 420;i ++); } void pressSensorInit(PRESS_EN_SENSOR_TYPY *penPressSensorTyep) { unsigned charbRet = false; // -- i2cInit();修改 BMP388_IIC_Init(); bRet = bmp388Check(); if( true == bRet) { *penPressSensorTyep = PRESS_EN_SENSOR_TYPY_BMP388; bmp388Init(); } else { *penPressSensorTyep = PRESS_EN_SENSOR_TYPY_MAX; } } void pressSensorDataGet(int32_t* ps32Temp, int32_t* ps32Press, int32_tps32Alti) { bmp388DataGet( ps32Temp, ps32Press, ps32Alti); return; } /***************************************************************************** BMP388 sensor device * ******************************************************************************/ static unsigned charbmp388Check(void) { unsigned charbRet = false; if(BMP388_REG_VAL_WIA == I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_WIA)) { bRet = true; } return bRet; } static uint8_t bmp388Init(void) { uint8_t u8RegData; uint8_t u8Ret; //reset u8RegData = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_STATUS); if( u8RegData & BMP388_REG_VAL_CMD_RDY ) { I2C_WriteOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_CMD, BMP388_REG_VAL_SOFT_RESET); BMP388_IIC_Delay(5); u8RegData = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_ERR); if( u8RegData & BMP388_REG_VAL_CMD_ERR) { u8Ret =0; return u8Ret; } } //calibration data read bmp388GetCalibrationData(); //seting I2C_WriteOneByte( I2C_ADD_BMP388, BMP388_REG_ADD_PWR_CTRL, BMP388_REG_VAL_PRESS_EN | BMP388_REG_VAL_TEMP_EN | BMP388_REG_VAL_NORMAL_MODE); return 0; } static void bmp388DataGet(int32_t* ps32Temp, int32_t* ps32Press, int32_t*ps32Alti) { uint32_t u32TempRegData, u32PressRegData; uint8_t u8Xlsb, u8Lsb, u8Msb; int32_t s32Pressure0 = 101325;// Mean Sea Level Pressure = 1013.25 hPA (1hPa = 100Pa = 1mbar) int32_t s32Temp, s32Press, s32Alti; u8Xlsb= I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_TEMP_XLSB); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_TEMP_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_TEMP_MSB); u32TempRegData = u8Msb; u32TempRegData <<= 8; u32TempRegData |= u8Lsb; u32TempRegData <<= 8; u32TempRegData |= u8Xlsb; u8Xlsb= I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_PRESS_XLSB); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_PRESS_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_PRESS_MSB); u32PressRegData = u8Msb; u32PressRegData <<= 8; u32PressRegData |= u8Lsb; u32PressRegData <<= 8; u32PressRegData |= u8Xlsb; s32Temp= bmp388CompensateTemp(u32TempRegData); s32Press = bmp388CompensatePress(u32PressRegData); s32Alti= 4433000 * (1 - pow((float)((float)((float)(s32Press)/100.0f) / (float)s32Pressure0), 0.1903)); bmp388CalAvgValue( &(gsstBMP388AvgFilter[0].u8Index), gsstBMP388AvgFilter[0].s32AvgBuffer, s32Temp,ps32Temp ); bmp388CalAvgValue( &(gsstBMP388AvgFilter[1].u8Index), gsstBMP388AvgFilter[1].s32AvgBuffer, s32Press, ps32Press); bmp388CalAvgValue( &(gsstBMP388AvgFilter[2].u8Index), gsstBMP388AvgFilter[2].s32AvgBuffer, s32Alti,ps32Alti ); return; } static void bmp388GetCalibrationData(void) { uint8_t u8Lsb, u8Msb; u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T1_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T1_MSB); gsstCali.T1 = u8Msb; gsstCali.T1 <<= 8; gsstCali.T1 |= u8Lsb; u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T2_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T2_MSB); gsstCali.T2 = u8Msb; gsstCali.T2 <<= 8; gsstCali.T2 |= u8Lsb; u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_T3); gsstCali.T3 = (int8_t)(u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P1_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P1_MSB); gsstCali.P1 = (int16_t)(u8Msb << 8 | u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P2_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P2_MSB); gsstCali.P2 = (int16_t)(u8Msb << 8 | u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P3); gsstCali.P3 = (int8_t)(u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P4); gsstCali.P4 = (int8_t)(u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P5_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P5_MSB); gsstCali.P5 = (u8Msb << 8 | u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P6_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P6_MSB); gsstCali.P6 = (u8Msb << 8 | u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P7); gsstCali.P7 = (int8_t)(u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P8); gsstCali.P8 = (int8_t)(u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P9_LSB); u8Msb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P9_MSB); gsstCali.P9 = (int16_t)(u8Msb << 8 | u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P10); gsstCali.P10 = (int8_t)(u8Lsb); u8Lsb = I2C_ReadOneByte(I2C_ADD_BMP388, BMP388_REG_ADD_P11); gsstCali.P11 = (int8_t)(u8Lsb); return; } static int64_t bmp388CompensateTemp(uint32_t u32RegData) { uint64_t partial_data1; uint64_t partial_data2; uint64_t partial_data3; int64_t partial_data4; int64_t partial_data5; int64_t partial_data6; int64_t comp_temp; partial_data1 = (uint64_t)(u32RegData - (256 * (uint64_t)(gsstCali.T1))); partial_data2 = (uint64_t)(gsstCali.T2 * partial_data1); partial_data3 = (uint64_t)(partial_data1 * partial_data1); partial_data4 = (int64_t)(((int64_t)partial_data3) * ((int64_t)gsstCali.T3)); partial_data5 = ((int64_t)(((int64_t)partial_data2) * 262144) + (int64_t)partial_data4); partial_data6 = (int64_t)(((int64_t)partial_data5) / 4294967296); /* Store t_lin in dev. structure for pressure calculation */ gsstCali.T_fine = partial_data6; comp_temp = (int64_t)((partial_data6 * 25)/ 16384); return comp_temp; } static int64_t bmp388CompensatePress(uint32_t u32RegData) { int64_t partial_data1; int64_t partial_data2; int64_t partial_data3; int64_t partial_data4; int64_t partial_data5; int64_t partial_data6; int64_t offset; int64_t sensitivity; uint64_t comp_press; partial_data1 = gsstCali.T_fine * gsstCali.T_fine; partial_data2 = partial_data1 / 64; partial_data3 = (partial_data2 * gsstCali.T_fine) / 256; partial_data4 = (gsstCali.P8 * partial_data3) / 32; partial_data5 = (gsstCali.P7 * partial_data1) * 16; partial_data6 = (gsstCali.P6 * gsstCali.T_fine) * 4194304; offset = (int64_t)((int64_t)(gsstCali.P5) * (int64_t)140737488355328) + partial_data4 + partial_data5 + partial_data6; partial_data2 = (((int64_t)gsstCali.P4) * partial_data3) / 32; partial_data4 = (gsstCali.P3 * partial_data1) * 4; partial_data5 = ((int64_t)(gsstCali.P2) - 16384) * ((int64_t)gsstCali.T_fine) * 2097152; sensitivity = (((int64_t)(gsstCali.P1) - 16384) * (int64_t)70368744177664) + partial_data2 + partial_data4 + partial_data5; partial_data1 = (sensitivity / 16777216) * u32RegData; partial_data2 = (int64_t)(gsstCali.P10) * (int64_t)(gsstCali.T_fine); partial_data3 = partial_data2 + (65536 * (int64_t)(gsstCali.P9)); partial_data4 = (partial_data3 * u32RegData) / 8192; partial_data5 = (partial_data4 * u32RegData) / 512; partial_data6 = (int64_t)((uint64_t)u32RegData * (uint64_t)u32RegData); partial_data2 = ((int64_t)(gsstCali.P11) * (int64_t)(partial_data6)) / 65536; partial_data3 = (partial_data2 * u32RegData) / 128; partial_data4 = (offset / 4) + partial_data1 + partial_data5 + partial_data3; comp_press = (((uint64_t)partial_data4 * 25) / (uint64_t)1099511627776); return comp_press; } static void bmp388CalAvgValue(uint8_t *pu8Index, int32_t *ps32AvgBuffer, int32_t s32InVal, int32_t *ps32OutVal) { uint8_t i; *(ps32AvgBuffer + ((*pu8Index) ++)) = s32InVal; *pu8Index &= 0x07; *ps32OutVal = 0; for(i = 0; i < 8; i ++) { *ps32OutVal += *(ps32AvgBuffer + i); } *ps32OutVal >>= 3; return; } ` BMP388 的驅(qū)動代碼圖 產(chǎn)品的意義 以某山區(qū)高速公路隧道為例,在安裝監(jiān)測終端之前,隧道管理部門主要依靠人工巡檢來監(jiān)測氣壓變化,不僅耗費大量人力物力,而且監(jiān)測頻率低、時效性差。一旦遇到惡劣天氣或者突發(fā)事故,很難及時掌握隧道內(nèi)氣壓的異常波動,給應急處置帶來極大困難。 安裝了遠程隧道氣壓監(jiān)測終端后,情況得到了顯著改善。在一次暴雨引發(fā)的山體滑坡事故中,隧道一端入口附近堆積了大量土石,導致氣流受阻,隧道內(nèi)氣壓急劇變化。監(jiān)測終端憑借其高精度的氣壓傳感器,迅速捕捉到了這一異常,在短短幾分鐘內(nèi)就通過 4G 網(wǎng)絡將氣壓數(shù)據(jù)和警報信息發(fā)送至監(jiān)控中心。監(jiān)控中心工作人員根據(jù)實時數(shù)據(jù),第一時間采取了交通管制措施,引導車輛有序疏散,避免了因氣壓問題導致駕駛員身體不適以及可能發(fā)生的車輛碰撞事故,同時也為后續(xù)的搶險救援工作提供了有力的數(shù)據(jù)支持,保障了人員的生命財產(chǎn)安全。 又如,某城市地鐵隧道在日常運營中,由于列車頻繁進出站,隧道內(nèi)氣流復雜,氣壓波動頻繁。以往由于缺乏精準的氣壓監(jiān)測手段,隧道襯砌的微小損壞難以被及時發(fā)現(xiàn),日積月累,對隧道結(jié)構安全構成潛在威脅。引入該監(jiān)測終端后,通過長時間、連續(xù)的數(shù)據(jù)采集與分析,運營方能夠清晰地掌握氣壓變化規(guī)律,提前發(fā)現(xiàn)因氣壓異常引發(fā)的襯砌結(jié)構應力變化,及時安排維護檢修,有效延長了隧道的使用壽命,降低了運營風險。 通過這些實際案例可以看出,基于 STM32H7R3 的遠程隧道氣壓監(jiān)測終端就如同隧道的 “安全衛(wèi)士”,無論是應對突發(fā)災害還是保障日常運營,它都能以精準的數(shù)據(jù)、高效的傳輸和穩(wěn)定的性能,全方位提升隧道的安全性與可靠性,讓我們的出行更加安心。 附件: *附件:STM32H7R3-BMP388.rar
    發(fā)表于 01-04 11:18

    KT148A語音芯片的7腳VDDIO平時是2.8V,響語音時變成3.3V是為什么呢

    KT148A語音芯片的7腳=VDDIO,是KT148A芯片內(nèi)部的LDO輸出引腳,是芯片的電源輸出 而8腳,才是電源的輸入端 。但是這里面還有使用細節(jié),詳見“問題集錦2”
    的頭像 發(fā)表于 01-04 11:11 ?43次閱讀
    KT148A語音芯片的7腳VDDIO平時是2.8V,響語音時變成3.3V是為什么呢

    磁柵芯片KMXP2000/5000國產(chǎn)替代方案VCP1612/1615

    迪仕科技VCP1612和VCP1615是兩款高精度的線性位置傳感器磁柵芯片,種能夠依據(jù)磁場強度改變輸出電壓的傳感器,通常由兩個正交方向上的磁性標尺構成。當磁柵尺與磁頭(通常內(nèi)置于磁柵芯片中)相對移動時,磁頭會檢測到磁場的變化,并將其轉(zhuǎn)換為電信號。這個電信號隨后被磁柵芯片內(nèi)的信號處理器分析,以計算出被測量目標的位移和運動方向。它們都采用了各向異性磁阻(AMR)技術。
    的頭像 發(fā)表于 01-04 11:07 ?68次閱讀
    磁柵芯片KMXP2000/5000國產(chǎn)替代方案VCP1612/1615

    天璣8400-Ultra全大核CPU加持,REDMI Turbo 4體驗拉滿

    手機市場在2025年迎來新的升級賽道,各廠商紛紛在性能和設計上尋求突破。REDMI推出的Turbo 4,首發(fā)搭載天璣8400-Ultra芯片,通過全面優(yōu)化的硬件配置和設計語言,在中高端市場搶占了先機。極簡設計和高能效性能相輔相成,展現(xiàn)了對目標用戶需求的深刻洞察。
    的頭像 發(fā)表于 01-04 10:59 ?85次閱讀

    霍爾元件DH188在冰淇淋機中的應用

    霍爾元件DH188在冰淇淋機中扮演著重要的角色,其應用主要體現(xiàn)在冰淇淋機的攪拌機中,用于測量轉(zhuǎn)速。以下是對霍爾元件在冰淇淋機中應用的詳細分析:
    的頭像 發(fā)表于 01-04 10:58 ?66次閱讀

    USB免驅(qū)IC讀卡器QT小程序開發(fā)

    FM1208CPU卡是一款由上海復旦微電子股份有限公司(Fudan Microelectronics Group, FMG)研發(fā)的高端智能非接觸CPU卡芯片。
    的頭像 發(fā)表于 01-04 10:55 ?59次閱讀
    USB免驅(qū)IC讀卡器QT小程序開發(fā)

    BT131可控硅參數(shù)

    BT131可控硅是一種常用的半導體器件,具有可控性強、穩(wěn)定性好等特點,廣泛應用于電力電子、自動化控制、照明等領域。
    的頭像 發(fā)表于 01-04 10:52 ?45次閱讀
    BT131可控硅參數(shù)

    霍爾元件DH45L在汽車安全帶鎖扣中的應用

    霍爾元件是一種基于霍爾效應的傳感器,能夠測量磁場的強度、方向和極性,因其工作原理簡單且性能優(yōu)良,被廣泛應用于多個領域。在現(xiàn)代汽車安全系統(tǒng)設計中,霍爾技術的應用尤為關鍵,特別是在安全帶鎖扣的設計上,霍爾元件扮演著至關重要的角色。
    的頭像 發(fā)表于 01-04 10:50 ?66次閱讀

    霍爾開關DH188:汽車后視鏡的智能革新

    霍爾開關在汽車后視鏡中的應用,是現(xiàn)代汽車技術發(fā)展的一個重要體現(xiàn)。通過精確控制和監(jiān)測后視鏡位置,霍爾開關不僅提高了駕駛的便利性,還增加了車輛的安全性能。
    的頭像 發(fā)表于 01-04 10:49 ?64次閱讀

    華普微榮獲南山區(qū)“綠色通道”企業(yè)榮譽稱號

    近日,經(jīng)深圳市南山區(qū)人民政府核定,南山區(qū)企業(yè)發(fā)展服務中心王部長向深圳市華普微電子股份有限公司成功授予了2024-2026年度“綠色通道”企業(yè)榮譽稱號。這一榮譽不僅是對華普微長期以來銳意進取與綜合實力的有力見證,也是對公司持續(xù)創(chuàng)新與不斷進步的有力激勵。
    的頭像 發(fā)表于 01-04 10:47 ?53次閱讀