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