STM8學習經(jīng)驗
第一節(jié): 心情和時鐘
我只是想和大大們交流一下,哪怕是對的或者是錯的,大大們滿足我的一點心愿吧。
嘮叨了這么多,現(xiàn)在開始吧。
配置:stvd,cosmic
我學單片機開門三磚總是要砸的。
第一磚:電源系統(tǒng),這沒什么好說的,只是它是stm8工作的基礎(chǔ)總是要提一下
第二磚:時鐘系統(tǒng),這等下再說。
第三磚:復(fù)位系統(tǒng),stm8只需要一只104電容從reset腳到地就可以了。
現(xiàn)在說說時鐘系統(tǒng),學習單片機無論8位的還是32位的,都要從時鐘開始,下面是我一開始的時鐘切換程序。
1CLK_ECKR |=0X1;//開啟外部時鐘
2while(!(CLK_ECKR&0X2)); //等待外部時鐘rdy
3CLK_CKDIVR &= 0XF8;//CPU無分頻
4CLK_SWR = 0XB4;//選擇外部時鐘
5CLK_SWCR |=0X2;//使能外部時鐘
上面的代碼看起來沒什么問題,可在調(diào)試過程中出現(xiàn)了有時能切換,有時有不能的情況,后來發(fā)現(xiàn)只要在第5行設(shè)上斷點就能切換,我就想是不是得讓cpu等一下,我又仔細的翻看下rm0016的時鐘部分,發(fā)現(xiàn)得等待CLK_SWCR的標志位置位才能切換。
就變成了下面的代碼
CLK_ECKR |=0X1;//開啟外部時鐘
while(!(CLK_ECKR&0X2)); //等待外部時鐘rdy
CLK_CKDIVR &= 0XF8;//CPU無分頻
CLK_SWR = 0XB4;//選擇外部時鐘
while(!(CLK_SWCR&0X8)); //這里要等
CLK_SWCR |=0X2;//使能外部時鐘
現(xiàn)在一切ok,是不是覺得看東西要仔細一下~~。順便說一下,stm8有三個時鐘源的,hse是外部時鐘,hsi是內(nèi)部16mhz的時鐘。Stm8一啟動默認為內(nèi)部時鐘,并且8分頻。
其實這么處理不是最好的辦法,如果外部時鐘出了問題,stm8要傻傻的等待到死。它可以有中斷的,在中斷中處理一切,包括恢復(fù)時鐘源,這才是正道,只是我比較懶,不是做正規(guī)產(chǎn)品,想都不愿去想。
長長的一篇,沒什么內(nèi)容,請原諒我的嘮叨吧。
又想起一句,仔細看手冊里的時鐘概略圖吧,這對你有幫助。
第二節(jié):傻的可愛—cosmic和time的事情
使用單片機定時器總是用到的,無論是延時,鍵盤掃描,顯示刷新,還是巨無霸的操作系統(tǒng)。Time1太過復(fù)雜等過些天再說,我是從time2開始的,從簡單的定時開始吧。
簡單的解釋一下,time2是向上計數(shù)的,不像time1可以雙向計數(shù)(這對我很有用,我可以使用它的正交編碼功能,這正是我學stm8的初衷,它可以讓我省下一片正交計數(shù)器或是一片cpld,等過兩天從公司借個編碼器,調(diào)試一下),我們怎么可以達到定時1ms的目的哪?
關(guān)鍵是TIM2_ARR這個寄存器,TIM2_CNTR是計數(shù)到TIM2_ARR就產(chǎn)生更新事件,然后清零從頭開始的,看下面的代碼。
1 CLK_PCKENR1 |=0X20;//開啟時鐘,stm8的外設(shè)時鐘可控
2 TIM2_PSCR |=0X3; //DIV81US ->外部晶振8mhz除以8實現(xiàn)單位時間為1us
3 TIM2_IER |= 0X1; //允許中斷
4 TIM2_ARR = 0X3E7;//關(guān)鍵是這里
5 TIM2_CR1 |= 0X1;//開啟定時器
這看起來沒錯,可就是不能實現(xiàn)定時效果,這是為什么?答案出乎我的意料,看匯編代碼后才發(fā)現(xiàn),comsic使用了ldw指令,而ldw指令是先寫低位再寫高位的。ARR寄存器是要求先寫高位再寫低位的,將第4行改為
TIM2_ARRH = 0X3;//
TIM2_ARRL = 0XE7;
后,問題解決。用avr時gcc編譯器都給做好了,comsic很傻很強大。記住這個教訓(xùn)吧,要看編譯器手冊,不要偷懶,多寫一行就多寫一行吧。中斷部分以后再說。就到這里,明天再聊,這耽誤我看小說的時間了,哎,為了stm8我已經(jīng)4晚上沒看小說了。
第三節(jié):ad的單次轉(zhuǎn)換
說起ad我是就頭大,不是說stm8的ad讓我頭大,而是以前在產(chǎn)品中使用的ad
老板總是要求越來越高,從16bit到24bit,從逐漸逼近到sigma,在電路上克服小信號的采集實在是一件痛苦的事情,至今在24bit的采集上只能到18bit有效位,有經(jīng)驗的朋友一定要告訴我。
又扯遠了,stm8只是10bit的ad,隨便用用就可以了,我從來沒指望它能給我出大力氣,當然大大們做民品,或是別的要求不高的可以用用。
為什么說單次轉(zhuǎn)換呢?因為簡單,因為我懶??聪旅娴拇a吧
//這里是初始化
CLK_PCKENR2 |=0X8; //使能adc時鐘
ADC_CSR|=0X3;//選擇通道3禁止中斷
ADC_CR1 |=0X71;//使能ADC,18分頻
ADC_CR2 |=0X8;//數(shù)據(jù)右對齊,low 8BITATADC_DRL;
//這里是轉(zhuǎn)換結(jié)果
unsigned int x;
unsigned int x_h;
ADC_CR1 |=0X1;//啟動轉(zhuǎn)換
while(!(ADC_CSR&0x80)); //等待轉(zhuǎn)換結(jié)束14個時鐘周期
ADC_CSR &= 0X7F;//清除中斷標志
x = ADC_DRL;//READ DATA因為是右對齊所以先讀低位
x_h = ADC_DRH;
x_h =( x_h << 8 ) + x;
return x_h;
這次沒出什么錯,大家失望了吧!哈哈,說點題外話,做16bit以上ad我認為要注意幾點
1.有一個好的基準
2.傳感器供電最好和基準聯(lián)動
3.要有效去除長線干擾,如加屏蔽網(wǎng),做線阻平衡。
4.使上兩個好的電阻吧,會省很大力氣
5.布線要花大力氣,不能瞎布。
其它的還有很多,大大們到網(wǎng)上看吧,前人栽樹,后人乘涼。我們即要做前人,也要做后人。
第四節(jié):中斷系統(tǒng)和一杯熱茶
最近喜歡喝茶,準備去買一套茶具,一個小壺,八個小杯那種。我喜歡鐵觀音,濃濃的,滾燙的,直入喉嚨。
中斷就像一杯濃濃的鐵觀音,沒有操作系統(tǒng)的時候,使用中斷吧,一樣可以達到實時響應(yīng)。沒有極品龍井,就喝鐵觀音吧,一樣口齒留香。
Stm8的中斷是有優(yōu)先級的,不是avr那種假優(yōu)先級,是那種低級中斷正在處理,高級中斷可以終止它的優(yōu)先級。
我們不說這些,它在不做項目時,離我還很遙遠。
說說comsic的開中斷手段吧看下面的語句
_asm("sim"); //這是關(guān)中斷
_asm("rim");//這是開中斷
我剛開始還以為sim是開中斷,結(jié)果定時中斷總是進不去。
_asm()插入?yún)R編行,多行可以用n分割
匯編塊可以使用下面格式
#asm
//匯編代碼
#endasm
或者
#pragmaasm
#pragmaendasm
Stvd自帶了中斷處理文件,在向量表里修改中斷號處的函數(shù)名,來實現(xiàn)中斷發(fā)生時程序跳到我們的中斷處理程序。
我寫了前面關(guān)于time2的更新中斷。
向量表中irq13處改成這樣{0x82, TIME2_UIS},
@far @interrupt void TIME2_UIS ( void )
{
if( ++count>temp)
{
count = 0;
PD_ODR ^=0X1; //LED翻轉(zhuǎn)
}
TIM2_SR1 &=0XFE; //中斷標志位,它不會自動清零
return;
}
Temp是前面ad轉(zhuǎn)換的結(jié)果,這里來實現(xiàn)led的閃爍頻率。@far是指長指針,@interrupt指示這是一個中斷處理函數(shù)。
本來還想說uart的中斷的,又一想明天我說uart的時候說啥。所以還是留在明天再說吧。
茶喝的多,睡眠質(zhì)量受影響啊。
第五節(jié): 永恒的串口和階段感言
等說完串口,就要等一些天再和大家見面了,孩子總是和我搗亂,那是我的第一生命。
是我祖祖輩輩的延續(xù)。請原諒我的古老,我喜歡傳統(tǒng)的,無論是京劇,大鼓還是快板。說起孩子,心情總是愉快的,有一天孩子感冒去醫(yī)院,醫(yī)生要驗血,臨近化驗室時,孩子哭鬧,妻子哄騙說是妻子驗血,等抽完孩子的血孩子哇哇大哭并質(zhì)問:“為什么你化驗抽我的血”我和妻子苦笑?,F(xiàn)在想來,孩子那時天真可愛,現(xiàn)在的孩子儼然一副大人麼樣,他才4歲呀,是我做的不好嗎?我從來不讓他在家做和玩耍無關(guān)的事情,包括學習。別家的孩子大都報各種專長班,我從來都阻止妻子去給孩子增加負擔。我要他的童年快快樂樂。我要讓他童年充滿童真,可是我做不到。孩子越來越聰明,越來越成熟,是我們老了嗎?
又跑題了,串口,自從我開始開發(fā)產(chǎn)品從來沒離開過串口。因為我總要和計算機或其他的mcu說話,而串口是最簡單和經(jīng)濟的方式。
傳統(tǒng)的也是最難舍棄,stm8的串口資源很豐厚,都有兩個。好些年前,要用雙串口除了使用專業(yè)芯片外只能選擇華邦的芯片,說實話它那時真的很貴。Avr也有雙串口的,所以我一見雙串口的芯片,總是興奮。大概得了串口恐懼癥了。
看代碼:
CLK_PCKENR1 |= 0X08; //開啟時鐘
LINUART_BRR2 = 0X1;
LINUART_BRR1 = 0X1A;//19200BPS
LINUART_CR2 = 0XAC;//8,n,1開啟發(fā)送和接受中斷
上面是初始化部分,很是簡單自己看看吧。
我接下來要用串口中斷做的事情很無聊,我要實現(xiàn)無論串口接收到一個什么數(shù)據(jù),都要返回該數(shù)據(jù)并加發(fā)0x55,0xaa。實時上這個協(xié)議一點用處都沒有,我希望大家開發(fā)產(chǎn)品的時候有串口協(xié)議時,如果資源夠用,又不愿自己寫時,使用modobus協(xié)議吧,真的很好用。
下面是中斷程序
@far @interrupt void USART_TX( void )
{
switch( status )
{
case 0:
LINUART_DR = 0X55;
status = 1;
break;
case 1:
LINUART_DR = 0XAA;
status = 2;
break;
case 2:
LINUART_CR2 = 0X2C;//數(shù)據(jù)空中斷只能寫dr清除,所以只能禁止它
status = 0;
break;
}
return;
}
@far @interrupt void USART_RX(void )
{
unsigned char x;
x = LINUART_DR ;//讀數(shù)據(jù)自動清除中斷標志
LINUART_DR = x;//同時清除發(fā)送空中斷標志
LINUART_CR2 = 0XAC;//所以可以打開發(fā)送空中斷了
status = 0;
return;
}
同樣在向量表中改成這樣
{0x82, USART_TX},
{0x82, USART_RX},
在這個簡單的基礎(chǔ)上,就可以開發(fā)自己的協(xié)議了。我用串口只使用這么多功能,別的如lin,idra,或是別的都是以后的事了。
和兄弟們說聲再見,下次在寫時就是正交編碼和spi了。
感謝壇子里的兄弟,你們在開拓大家的視野
感謝阿莫,買套件時居然有三個免費的芯片,雖然別人也有,但我買時不知道,算是驚喜
感謝我的孩子,經(jīng)常給我搗亂,讓我覺得我依然是個好父親
感謝我的雙眼,我今天見到了白里透著紅的美女
第五節(jié): 正交編碼和疑惑
今天去公司,找遍了廢品堆都沒有找到一只編碼器,沒辦法只好從半成品上拆下來一個,大家不要說是我做的,不然老板會很生氣。
正交計數(shù)方法很多,軟件的,cpld的,芯片的都可以,但cpu上集成了我們?yōu)槭裁床挥茫覜]理由不選帶正交功能的stm8,因為他是8bit的,因為他價格據(jù)說很便宜,32bit的cpu大多是帶這個功能的包括dsp,我總是說在我的產(chǎn)品里他是大馬,我的產(chǎn)品是小車,其實是我不愿去啃32bit的大部頭。寫完這篇我下定決心要使用stm32了
到時候兄弟們一定要幫助我,就當是扶貧吧。
阿莫的三合一板使用的芯片是s207s8t6,44腳的,time1的兩個輸入段為pc1,和pc2,我將編碼器的a,b相分別接在PC1,PC2上。接上VCC和gnd,電路的工作
算是完成,接下來都是軟件的工作。
在此之前看看stm32的正交編碼接口應(yīng)用筆記吧,上面對原理描述的很清楚,比我說的要有條理,我就不說了??聪旅娴拇a
//下面是初始化部分
CLK_PCKENR1 |=0X80; //開啟time1時鐘
TIM1_SMCR |= 0X3;//工作在編碼器模式3
TIM1_CCMR1 |= 0X1;//CC1 MAP TI1FP1CH1
TIM1_CCMR2 |= 0X1; //CC2 MAPTI2FP2CH2
TIM1_ARRH = 0XEA;// 60000產(chǎn)生溢出
TIM1_ARRL = 0X60;
TIM1_IER |=0X1;//開中斷
TIM1_CNTR = cnt_start = 30000; //我要有個大的初始化值
//正好是滿量程的一半
TIM1_CR1 =0X1;//啟動計數(shù)
通過上面簡單的配置,time1正是工作了,旋動編碼器,可以看到TIM1_CNTR的數(shù)據(jù)變動,我的1000線編碼每轉(zhuǎn)一圈產(chǎn)生4000個數(shù)。
在我的中斷和主程序里做了處理,可計數(shù)范圍擴展到32bit,算是基本達到了我的要求。有一件事要說一下,讀TIM1_CNTR時要先讀高位,再讀低位。