從51開始,單片機玩了很長時間了,有51,PIC,AVR等等,早就想跟潮流玩玩ARM,但一直沒有開始,原因 -----不知道玩了ARM可以做什么(對我自己而言)。如果為學習而學習,肯定學不好。然后cortex-m3出來了,據說,這東西可以替代單片機,于 是馬上開始關注。也在第一時間開始學習,可惜一開始就有點站錯了隊,選錯了型(仍是對我自己而言)。我希望這種芯片應該是滿大街都是,隨便哪里都可以買得 到,但我選的第一種顯然做不到。為此,大概浪費了一年多時間吧,現(xiàn)在,回到對我來說是正確的道路上來啦,邊學邊寫點東西。
閑話多了些,就權當前言了。下面準備開始。
?
BKP還沒有搞完,怎么又換到了RTC上了,因為RTC和BKP有些聯(lián)系,想不關聯(lián)還不行呢。
以下是數據手冊上有關RTC的介紹:
******介紹開始
15.1 RTC 簡介
實時時鐘是一個獨立的定時器。RTC模塊擁有一組連續(xù)計數的計數器,在相應軟件配置下,可提供時鐘日歷的功能。修改計數器的值可以重新設置系統(tǒng)當前的時間和日期。
RTC模塊和時鐘配置系統(tǒng)(RCC_BDCR寄存器)是在后備區(qū)域,即在系統(tǒng)復位或從待機模式喚醒后RTC的設置和時間維持不變。
系統(tǒng)復位后,禁止訪問后備寄存器和RTC,防止對后備區(qū)域(BKP)的意外寫操作。執(zhí)行以下操作使能對后備寄存器和RTC的訪問:
● 設置寄存器RCC_APB1ENR的PWREN和BKPEN位來使能電源和后備接口時鐘
● 設置寄存器PWR_CR的DBP位使能對后備寄存器和RTC的訪問。
******介紹結束
下面就以庫中所帶的實例來玩這個RTC,正好也要解決TAMPER引腳的問題。
這次要用到的例子是這個:
有關配置沒有什么可多說的,把上一個例子:BKP-》Backup_Data中修改過的:
stm32_eval.c
stm3210e_eval.h
stm32_eval.h
三個文件復制過來,建立工程,一路順風,非常順利地編譯、鏈接好,然后進入調試,結果,出問題了,見下面:
進入調試界面即停在了反匯編界面。一旦執(zhí)行程序,立即就停下來。這個BKPT指令是個什么東西呢?查了一下指令表,原來是個斷點指令,那為什么會停止在這里呢?萬能的網啊,一搜就出來了,感謝前人的努力,感謝偉大的網。..。
結論是:“ 凡是用到printf的都會出現(xiàn)這樣的問題?!?/p>
解決方法:
打開Options for Target項,把那個Use MicroLIB前面打上勾,重新編譯鏈接即可。
出現(xiàn)問題的原因,網上的相關解釋是:這是Printf庫函數的問題,需要使用MicroLIB這個庫來替代默認的庫。原因是默認printf并非使用串口,所以要改掉。
在main.c中有這樣一段函數:
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(EVAL_COM1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET)
{}
return ch;
}
根據這段函數的說明,就是做這個事情的。
但是還有一些疑問:
?。?)這個例子的readme.txt中并沒有說明要用MicroLIB這個庫的事情。
?。?)如果不用硬件,而是用軟件仿真,也是不需要使用MicroLIB庫的。
因此,有關MicroLIB的問題還不是特別明確,還需要進一步研究。是否是這段程序還用到了scanf的原因?
例子的運行
如果是第一次運行,那么會出現(xiàn)如下畫面:
即其中有提示RTC沒有初始化,要求進行設置的提示,根據提示分別送入小時,分鐘,秒的數值,即完成設置工作,程序不斷地將當前時間通過串口送出。
如果在VBAT端接入后備電池,那么斷電后再上電顯示的信息如下:
其中提示RTC已初始化,不需要再進行初始化,直接將時間不斷地從串口送出。
程序解讀
/**
* @brief Configures the RTC.
* @param None
* @retval None
*/
void RTC_Configuration(void)
{
/* 開啟PWR和BKP模塊的時鐘 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* 允許對BKP進行存取操作*/
PWR_BackupAccessCmd(ENABLE);
/* 初始化BKP區(qū)域*/
BKP_DeInit();
/* LSE允許,這里LSE是指外部接的32768HZ 晶振的一個振蕩器,它使用PC14和PC15兩條引腳。有關這部分的一些細節(jié)描述如下:
當備份區(qū)域由V DD (內部模擬開關連到V DD )供電時,下述功能可用:
● PC14和PC15可以用于GPIO或LSE引腳
● PC13可以作為通用I/O口、TAMPER引腳、RTC校準時鐘、RTC鬧鐘或秒輸出
當后備區(qū)域由VBAT供電時(VDD消失后模擬開關連到VBAT),可以使用下述功能:
● PC14和PC15只能用于LSE引腳
● PC13可以作為TAMPER引腳、RTC鬧鐘或秒輸出
*/
RCC_LSEConfig(RCC_LSE_ON);
/* 等待LSE振蕩器就緒 */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{}
/* 選擇LSE作為RTC的時鐘源
說明:RTC時鐘源可以是以下三種之一:
─ HSE 時鐘除以 128
─ LSE 振蕩器時鐘
─ LSI振蕩器時鐘
其中LSI是一個內部的低頻RC振蕩器。關于RTC的這三個時鐘各有何特點,見下面的說明。
*/
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* RTC時鐘允許*/
RCC_RTCCLKCmd(ENABLE);
/* 等待RTC寄存器同步
理由如下:
15.3.3 讀 RTC 寄存器
RTC核完全獨立于RTC APB1接口。
軟件通過APB1接口訪問RTC的預分頻值、計數器值和鬧鐘值。但是,相關的可讀寄存器只在與RTC APB1時鐘進行重新同步的RTC時鐘的上升沿被更新。RTC標志也是如此的。
這意味著,如果APB1接口剛剛被開啟之后,在第一次的內部寄存器更新之前,從APB1上讀出RTC寄存器的第一個值可能被破壞了(通常讀到0)。下述幾種情況下能夠發(fā)生這種情形:
● 發(fā)生系統(tǒng)復位或電源復位
● 系統(tǒng)剛從待機模式喚醒(參見4.3節(jié))。
● 系統(tǒng)剛從停機模式喚醒(參見4.3節(jié))。
所有以上情況中,APB1接口被禁止時(復位、無時鐘或斷電)RTC核仍保持運行狀態(tài)。 因此,若在讀取RTC寄存器曾經被禁止的RTC APB1接口,軟件首先須等待RTC_CRL寄存器中
的RSF位(寄存器同步標志)被硬件置1。
{
/* Clear RSF flag */
RTC-》CRL &= (uint16_t)~RTC_FLAG_RSF;
/* Loop until RSF flag is set */
while ((RTC-》CRL & RTC_FLAG_RSF) == (uint16_t)RESET)
{
}
}
*/
RTC_WaitForSynchro();
/* 等待最后寫操作完成*/
RTC_WaitForLastTask();
/* 允許秒中斷,相應代碼如下:
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RTC_IT(RTC_IT));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RTC-》CRH |= RTC_IT;
}
else
{
RTC-》CRH &= (uint16_t)~RTC_IT;
}
}
而調用這段程序的代碼中的第一個參數是:
#define RTC_IT_SEC ((uint16_t)0x0001) /*!《 Second interrupt */
可見它是對RTC-》CRH的最低位進行操作,CRH相關內容見下面的圖。
*/
RTC_ITConfig(RTC_IT_SEC, ENABLE);
/* 等待最后的寫操作完成*/
RTC_WaitForLastTask();
/* 設置RTC預分頻器: set RTC period to 1sec */
RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
/* 等待最后的寫操作完成*/
RTC_WaitForLastTask();
}
下面的圖是有關RTC時鐘選擇的問題,其中說明了各種時鐘的工作特性:
下面的圖是有關RTC_CRH寄存器的描述,放在這里是為了說明SECIE標志位。
STM32單片機學習小Tips之數據的保存和毀滅(2)
和以前學到的有關數據保存不同,這里的數據保存還有“保密”之意,即一旦受到意外的侵入,STM32將毀滅數據。這是通過Tamper機制來實現(xiàn)的。
以下是數據手冊中的有關說明:
5.3.1 侵入檢測
當TAMPER引腳上的信號從0變成1或者從1變成0(取決于備份控制寄存器 BKP_CR的TPAL位),會產生一個侵入檢測事件。侵入檢測事件將所有數據備份寄存器內容清除。 然而為了避免丟失侵入事件,侵入檢測信號是邊沿檢測的信號與侵入檢測允許位的邏輯與,從而在侵入檢測引腳被允許前發(fā)生的侵入事件也可以被檢測到。
● 當 TPAL=0 時:如果在啟動侵入檢測TAMPER引腳前(通過設置TPE位)該引腳已經為高電平,一旦啟動侵入檢測功能,則會產生一個額外的侵入事件(盡管在TPE位置’1’后并沒有出現(xiàn)上升沿)。
● 當 TPAL=1 時:如果在啟動侵入檢測引腳TAMPER前(通過設置TPE位)該引腳已經為低電平,一旦啟動侵入檢測功能,則會產生一個額外的侵入事件(盡管在TPE位置’1’后并沒有出現(xiàn)下降沿)。
設置BKP_CSR寄存器的TPIE位為’1’,當檢測到侵入事件時就會產生一個中斷。
在一個侵入事件被檢測到并被清除后,侵入檢測引腳TAMPER應該被禁止。然后,在再次寫入備份數據寄存器前重新用TPE位啟動侵入檢測功能。這樣,可以阻止軟件在侵入檢測引腳上仍然有侵入事件時對備份數據寄存器進行寫操作。這相當于對侵入引腳TAMPER進行電平檢測。
注:當V DD電源斷開時,侵入檢測功能仍然有效。為了避免不必要的復位數據備份寄存器,TAMPER引腳應該在片外連接到正確的電平。
顯然,Tamper需要硬件與之配合。以上數據手冊描述了硬件配置時的一些注意事項。
?。?) 可以是把引腳由低電平到高電平認為是一次侵入,也可以把引腳從高電平變到低電平認為是一次侵入,這通過TPAL來設置。
(2) Tamper機制需要被啟動才能起作用。但在啟動之前,如果引腳已處于設定的狀態(tài),那么一旦啟動,就會產生一次Tamper事件,這需要注意,否則會引起數據的意外丟失而不自覺。
?。?) 即便芯片上的VDD電源斷開,(只要仍有VBAT),那么Tamper檢測仍是有效的,因此,設計硬件時必須要小心,如果某設計是將Tamper引腳通過上拉電阻接VDD,并在這個引腳上接入機械開關到地。如果開關導通,那么就是一次Tamper事件,這個沒有問題。但是,如果電源斷開(VDD變低),也會引發(fā)一次Tamper事件,而這往往并不是設計都的本意。因此,這個引腳的上拉電阻必須接到VBAT而不是接到VDD。
?。?) 總的來說,TAMPER并不復雜,下面來看一看代碼。
這次是用的STM32庫中的這個例子。
有關LED的設置,這里就不再重復了,和上一篇文章(數據的保存與毀滅(1)相同)。
/* Enable write access to Backup domain */
PWR_BackupAccessCmd(ENABLE);
這是打開BKP功能。
/* Clear Tamper pin Event(TE) pending flag */
BKP_ClearFlag();
清除Tamper事件
/* Tamper pin active on low level */
BKP_TamperPinLevelConfig(BKP_TamperPinLevel_Low);
配置Tamper引腳究竟是高電平有效還是低電平有效,這個再研究一下,繼續(xù)跟蹤:
/**
* @brief Configures the Tamper Pin active level.
* @param BKP_TamperPinLevel: specifies the Tamper Pin active level.
* This parameter can be one of the following values:
* @arg BKP_TamperPinLevel_High: Tamper pin active on high level
* @arg BKP_TamperPinLevel_Low: Tamper pin active on low level
* @retval None
*/
void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel)
{
/* Check the parameters */
assert_param(IS_BKP_TAMPER_PIN_LEVEL(BKP_TamperPinLevel));
*(__IO uint32_t *) CR_TPAL_BB = BKP_TamperPinLevel;
}
CR_TPAL_BB又是什么呢?
/* Alias word address of TPAL bit */
#define CR_OFFSET (BKP_OFFSET + 0x30)
#define TPAL_BitNumber 0x01
#define CR_TPAL_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (TPAL_BitNumber * 4))
要看懂上面有關CR_TPAL_BB的相關定義及理解為何這樣寫,恐怕又要涉及到Contex的另一個重要內容,即bit-band,這個暫不深究,留待下次學習(說句閑話:bit-bank我早就看到,就是沒有興趣深入了解,因為沒覺得什么地方有用到,今天既已知其用途,改日必去改看,,,所以只有動起來,才能學更多的東西)。這里只管當它是能夠直接設定該平是0或都是1就行了。
即根據實參決定BKP_CR中的TPAL究竟是0還是1??蛇x參數為:
#define BKP_TamperPinLevel_High ((uint16_t)0x0000)
#define BKP_TamperPinLevel_Low ((uint16_t)0x0001)
BKP的其他用途:
BKP的寄存器可以用來存儲RTC校驗值的校驗寄存器。
在PC13管腳(當該管腳不用于侵入檢測時)上輸出RTC校準時鐘,RTC鬧鐘脈沖或者秒脈沖
為方便測量,RTC時鐘可以經64分頻輸出到侵入檢測引腳TAMPER上。通過設置RTC校驗寄存器(BKP_RTCCR)的CCO位來開啟這一功能。 通過配置CAL[6:0]位,此時鐘可以最多減慢121ppm。
下面以RTC的那個例子為例,來看一看如何用Tamper(PC13)引腳來送出信號。
/* 打開PWR和KBP模塊的時鐘信號 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/*允許對BKP進行存取*/
PWR_BackupAccessCmd(ENABLE);
/* 禁止引腳的TAMPER功能*/
BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamper functionality must be disabled */
/* 允許時鐘信號在TAMPER引腳輸出*/
BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
這樣就可以了,也不復雜。
需要說明的一點是,PC13這個引腳不需要被配置成輸出引腳,但在這一時刻它是起到輸出作用的。
BKP_RTCOutputConfig()這個函數中所用到的參數可以有這樣的一些:
BKP_RTCOutputSource_None
不允許在Tamper引腳輸出信號
BKP_RTCOutputSource_CalibClock
在Tamper引腳上輸出RTC時鐘經64分頻后的頻率信號
BKP_RTCOutputSource_Alarm
在Tamper引腳上輸出RTC報警信號
RTCOutputSource_Second
在Tamper引腳上輸出秒信號
經測試,
?。?)在Tamper引腳上輸出的信號,不受復位的影響!當然,這是有條件的,條件是復位時不會執(zhí)行到操作RTC的相關代碼。
(2) 在用J-LINK寫入代碼時,Tamper引腳輸出的信號,不受影響,照樣輸出!
(3)斷電之后再上電,Tamper引腳送出的信號,不受影響,照樣輸出!
?。?) 去掉VBAT供電端的電力供應,斷電,再上電,Tamper引腳送出的信號消失!
判斷:前面的程序寫的有關標志被保存在BKP區(qū)域,不斷電不會消失。這是否對電池的壽命有影響呢?畢竟送出波形也會有消耗的。
最后用兩個圖來結束,分別是運行時的BKP內容和POWER,RESET,CLOCK的內容。
STM32單片機小Tips之玩轉IAR,開發(fā)STM32
記得本筆記開始時曾說過,我選用keil,理由是keil我熟,而當時我什么都不懂,總要找個熟悉點的東西,并且說過,如果需要用到IAR時,肯定上手也很快。這回要用IAR了,看一看上手究竟快不快啦!
資源列表:
芯片:STM32103VC
庫:3.3
JLINK:V8
IAR:5.3
工作目標:編譯庫中的例子。
工作過程:
?。?)文件夾結構
基本上沒有變化。
為什么要強調這個呢,這可和設置有很大的關系。
接下來看例子文件
其中上面的那個文件夾中包含了大量的例子,而下面的這個文件夾則包含了幾種編譯器的工程例子,里面有一些東西是我們需要用到的。
再繼續(xù)
這次偷了點懶,沒有專門為源程序建立一個文件夾,直接把工程文件和源程序文件放在一起了,當然,也有一個因素,是因為使用IAR默認設置就做得相當的“干凈”,編譯完了后基本上沒有多出幾個文件出來。要是keil,那可不得了,,,
在iar中用File-》New-》WorkSpace新建一個工作區(qū),然后用Project-》Creat New Project新建一個工程。
起名保存等等吧,這一類的問題就不在這里一一列出了。
總之我們做好了一個名為IOToggle的工程,然后就要將文件加入到工程中去了。
為了便于區(qū)分,同樣在IOToggle中建立3個組,如下圖所示。
將IOToggle文件夾中的所有C文件全部加入到APP組,同時再將
中的stm32_eval.c文件加入這個組中。
在CMSIS組中加入的文件是:
其中core_cm3.c在\Libraries\CMSIS\CM3\CoreSupport文件夾中,system_stm32f10x.c在\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x文件夾中,而startup_stm32f10x_hd.s在\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\iar中。
在LIB文件夾中加入的文件是:
這些文件當然都是3.3庫所提供的,在\Libraries\STM32F10x_StdPeriph_Driver\src文件夾中。
至此,文件加入完畢。
從下面開始有兩個選擇
1.直接使用J-LINK
接下是重要的設置工作。
接下來這里很重要
設定頭文件所在位置,這個如果設置不對,編譯不能通過。
$PROJ_DIR$\
設定項目所在位置,如果這個沒有的話,會找不到stm32f10x_it.h等頭文件。
$PROJ_DIR$\。.\。.\。.\。.\Libraries\CMSIS\CM3\CoreSupport
這里的。.\表示的是上級目錄的意思(DOS下的東西,曾經是那么的熟悉)
$PROJ_DIR$\。.\。.\。.\。.\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
$PROJ_DIR$\。.\。.\。.\。.\Libraries\STM32F10x_StdPeriph_Driver\inc
$PROJ_DIR$\。.\。.\。.\。.\Utilities\STM32_EVAL
其他的都不多說了,如果做其他工程時,目錄結構與上面的不相同,那么基于這些知識就能自行修改這些參數了。
在Defined sybols中預設了一個符號,這也是必須的,否則會有大量的編譯錯誤出現(xiàn)。
接下來,在Link中還有一個重要的設置:
需要更改override default的設置,不能使用其默認的設置。
這個EWARMv5在這里:\Project\STM32F10x_StdPeriph_Template\EWARMv5
要選擇這個stm32f10x_flash.icf替換掉原來的默認設置,這個其實就是準備向flash中寫代碼的。
接下來要設置的是Debugger。我們選擇
接著切換到Download
這里只要選中Use flash loader即可,不需要做修改。
接著可以到J-Link/J-Trace中去修改,不過,我用的都是默認的參數,沒有什么需要修改的。
2.使用RDI
如果不用J-Link,也可使用RDI設置
然后,單擊RDI,進入RDI設置
這個紅色框中的是需要自己找的,要找到SEGGER的安裝目錄,并找到這個DLL文件。
接著就會在右下角出現(xiàn)這個
單擊RDI,出來對話框
單擊Configuration進入設置界面
勾選Enable flash programming,然后選擇指定的芯片即可。
至此,IAR基本算是玩起來了。
?
評論
查看更多