|
IAR for AVR 學(xué)習(xí)筆記(1)--數(shù)據(jù)類型
數(shù)據(jù)類型(編譯器支持 ISO/ANSI C 基本數(shù)據(jù)類型和一些附加數(shù)據(jù)類型)
1.1. 整型數(shù)據(jù)

bool 數(shù)據(jù)類型在C++語言里是默認(rèn)支持的。如果你在C代碼的頭文件里包含stdbool.h, bool數(shù)據(jù)類型也可以使用在C語言里。也可以使用布爾值 false和
true。
1.2.浮點(diǎn)數(shù)據(jù)類型:

1.3.指針類型:指針有數(shù)據(jù)指針和函數(shù)指針。
1、數(shù)據(jù)指針:
數(shù)據(jù)指針的大小為8位,16位,24位。定義為:在整型數(shù)據(jù)類型后加”*”符號(hào)。
例如:char * p;
整型數(shù)據(jù)沒有24位,具體定義指針見后面擴(kuò)展關(guān)鍵字章節(jié)。
2、函數(shù)指針:函數(shù)指針的大小為16位,24位。
指針定義:在函數(shù)類型后加”*”符號(hào)
IAR for AVR 學(xué)習(xí)筆記(2)--擴(kuò)展關(guān)鍵字
可以用來解決數(shù)據(jù),函數(shù)的存放等。有了它我們就可以定義變量存放在EEPROM,FLASH空間。定義中斷函數(shù),指針等等。IAR關(guān)鍵字很多,這里只列舉常用的。
2.1.?dāng)U展關(guān)鍵字:用于控制數(shù)據(jù)和指針。
__eeprom 用于EEPROM 存儲(chǔ)空間, 控制數(shù)據(jù)存放,控制指針類型和存放
__tinyflash, __flash, __farflash, __hugeflash 用于flash 存儲(chǔ)空間, 控制數(shù)據(jù)存放,控制指針類型和存放:
__ext_io, __io 用于I/O存儲(chǔ)空間, 控制數(shù)據(jù)存放,控制指針類型和存放
__regvar 放置一個(gè)變量在工作寄存器中
2.2.函數(shù)擴(kuò)展關(guān)鍵字:。
__nearfunc __farfunc 用于控制數(shù)據(jù)存放,這組關(guān)鍵字必須在函數(shù)聲明和定義的時(shí)候指定:
__interrupt. 關(guān)鍵字控制函數(shù)的類型。這組關(guān)鍵字必須在函數(shù)聲明和定義的時(shí)候指定
__root. 關(guān)鍵字僅僅控制有定義的函數(shù):
2.3.其它特別的關(guān)鍵字:
@ 用于變量的絕對(duì)地址定位。也可以用#pragma location 命令
#pragma vector 提供中斷函數(shù)的入口地址。
__root 保證沒有使用的函數(shù)或者變量也能夠包含在目標(biāo)代碼中
__no_init 禁止系統(tǒng)啟動(dòng)的時(shí)候初始化變量.
asm, __asm 插入?yún)R編代碼
IAR for AVR 學(xué)習(xí)筆記(3)--位操作
3.1.在c語言里對(duì)位的操作如一般如下:
PORTB|=(1<<2);//置PORTB的第2位=1
PORTB&=~(1<<2);//置PORTB的第2位=0
PORTB^|=(1<<2);//取反PORTB的第2位
While(PORTB&(1<<2));//判斷1
While(!(PORTB&(1<<2)));//判斷為0
3.2.IAR編譯器對(duì)位的支持更強(qiáng)大,除了上面的方法外還有以下更簡(jiǎn)單的操作方法:
PORTB_ Bit2=1; //置PORTB的第2位=1
PORTB_ Bit2=0; //置PORTB的第2位=0
PORTB_ Bit2=~ PORTB_ Bit2;//取反PORTB的第2位
While(PORTB_ Bit2);或者while(PORTB_Bit2==1);//判斷1
while(PORTB_ Bit2==0);//判斷0
PORTC_Bit4=PORTB_Bit2;//把PORTB的第2位傳送到PORTC的第4位
3.3.位變量定義:
由于iar使用了擴(kuò)展語言,它對(duì)位域的支持變?yōu)樽钚?span lang="EN-US">char類型,我們可以很方便地用來定義位變量。
采用結(jié)構(gòu)體來定義位變量:
struct
{
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
}t;
然后就可以用以下位變量了。
t.bit0=1;
t.bit0=~t.bit0;
但是采用以上結(jié)構(gòu)體做出來的位變量只可以訪問t的位,不能夠直接訪問變量t,和標(biāo)準(zhǔn)的IAR位操作也不一樣。采用聯(lián)合體來定義效果更佳。
#i nclude<iom8.h>
union
{
unsigned char t;
struct
{unsigned char t_bit0:1,
t_bit1:1,
t_bit2:1,
t_bit3:1,
t_bit4:1,
t_bit5:1,
t_bit6:1,
t_bit7:1;
};
};
void main(void)
{
t_bit0=1;//訪問變量t的位
t_bit0=~t_bit0;
PORTB=t;//直接訪問變量t
}
位變量也可以直接定義在工作寄存器里。
3.4 bool 數(shù)據(jù)類型在C++語言里是默認(rèn)支持的。
如果你在C代碼的頭文件里包含stdbool.h, bool數(shù)據(jù)類型也可以使用在C語言里。也可以使用布爾值 false和 true。不過是占用8位1個(gè)字節(jié)。
#i nclude<iom8.h>
#i nclude<stdbool.h>
bool y=0;//定義位變量
void main(void)
{
y=!y;//取反位變量
PORTB_Bit3=y;//傳遞位變量
}
IAR for AVR 學(xué)習(xí)筆記(4)--Flash操作
FLASH常用類型的具體操作方法
4.1.FLASH 區(qū)域數(shù)據(jù)存儲(chǔ)。
用關(guān)鍵字 __flash 控制來存放, __ flash 關(guān)鍵字寫在數(shù)據(jù)類型前后效果一樣
__flash unsigned char a;//定義一個(gè)變量存放在flash空間
unsigned char __flash a;//效果同上
__flash unsigned char p[];//定義一個(gè)數(shù)組存放在flash空間
對(duì)于flash空間的變量的讀操作同SRAM數(shù)據(jù)空間的操作方法一樣,編譯器會(huì)自動(dòng)用
LPM,ELPM 指令來操作。
例:
#i nclude<iom8.h>
__flash unsigned char p[];
__flash unsigned char a;
void main(void)
{PORTB=p[1];// 讀flash 數(shù)組變量的操作
PORTB=a;// 讀flash 變量的操作
}
由于在正常的程序中,flash 空間是只讀的,所以沒有賦值的變量是沒有意義的。定義常數(shù)在flash 空間,只要給變量賦與初值就可以了。由于常數(shù)在flash空間的地址是隨機(jī)分配的,讀取變量才可以讀取到常數(shù)值。
10
IAR-AVR –C 編譯器簡(jiǎn)要指南
__flash unsigned char a=9;//定義一個(gè)常數(shù)存放在EEPROM空間。
__flash unsigned char p[]={1,2,3,4,5,6,7,8};
//定義一個(gè)組常數(shù)存放在flash 空間。
例:
#i nclude<iom8.h>
__flash unsigned char p[]={1,2,3,4,5,6,7,8};
__flash unsigned char a=9;
void main(void)
{
PORTB=a;//讀取flash 空間值9
PORTC=p[0]; //讀取flash 空間值
}
4.1.2flash 空間絕對(duì)地址定位:
__flash unsigned char a @ 0x8;//定義變量存放在flash 空間0X08單元__flash unsigned char p[] @ 0x22//定義數(shù)組存放在flash 空間,開始地址為0X22單元
__flash unsigned char a @ 0x08=9;//定義常數(shù)存放在flash 空間0X08單元
__flash unsigned char p[] @ 0x22={1,2,3,4,5,6,7,8};
//定義一個(gè)組常數(shù)存放在EEPROM空間開始地址為0X22單元
由于常數(shù)在flash 空間的地址是已經(jīng)分配的,讀取flash 空間值可以用變量和地址。
4.2.與 __flash 有關(guān)的指針操作。 __flash 關(guān)鍵字控制指針的存放和類型。
4.2.1指向flash 空間的指針flash 指針(控制類型屬性)
unsigned char __flash * p;//定義指向flash 空間地址的指針,8位。
unsigned int __flash * p;//定義個(gè)指向flash 空間地址的指針,16位。
unsigned int __farflash * p;//定義指向flash 空間地址的指針,24位。
unsigned int __hugeflash * p;//定義指向flash 空間地址的指針,24位。
unsigned char __flash * p;//定義一個(gè)指向flash 空間地址的指針,指針本身存放在SARM中。P的值代表flash 空間的某一地址。*p表示flash 空間該地址單元存放的內(nèi)容。例:假定p=10,表示flash空間地址10單元,而flash M空間10單元的內(nèi)容就用*p來讀取。
例:
#i nclude<iom8.h>
char __flash t @ 0x10 ;
char __flash *p ;
void main(void)
{
PORTB=*p;//讀取flash 空間10單元的值
PORTB=*(p+3);//讀取flash 空間0x13單元的值
}
4.2.2.存儲(chǔ)于flash 空間的指針數(shù)據(jù)指針
就象存儲(chǔ)與flash 空間的數(shù)據(jù)一樣控制存儲(chǔ)屬性
__flash unsigned char * p; //定義指向SARMM空間地址的指針,指針本身存放在flash 中。
4.3.控制數(shù)據(jù)和指針存放的__flash
定義必須是全局變量,控制類型屬性(好像只有指針)可以是局部變量。
#i nclude<iom8.h>
__flash unsigned char p;//控制存放
void main(void)
{
unsigned char __flash* t;//控制屬性
PORTB=p;
PORTB=*t;
}
4.4. __root 關(guān)鍵字保證沒有使用的函數(shù)或者變量也能夠包含在目標(biāo)代碼中.
定義存放在__flash 空間的數(shù)據(jù)在程序編譯時(shí)會(huì)自動(dòng)生成代碼嵌入到flash代碼中,對(duì)于程序沒有使用也要求編譯的數(shù)據(jù)(比如可以在代碼中嵌入你的版本號(hào),時(shí)間等)必須加關(guān)鍵字__root 限制。
例:
#i nclude<iom8.h>
__root __flash unsigned char p @ 0x10 =0x56;
void main(void)
{}
程序沒有使用P變量,編譯也會(huì)生成該代碼。
:020000020000FC
:1000000016C018951895189518951895189518955F
:10001000569518951895189518951895189518953A
:10002000189518951895089500008895FECF0FE94A
:100030000DBF00E00EBFC0E8D0E003D0F4DFF4DF76
:06004000F3CF01E008957A
:0400000300000000F9
:00000001FF
4.5.flash 操作宏函數(shù):在comp_a90.h intrinsics.h頭文件里有詳細(xì)說明。flash 空間具正常情況下有只讀性能,對(duì)于讀flash 數(shù)據(jù)編譯器會(huì)自動(dòng)編譯對(duì)應(yīng)的LPM,ELPM指令,但對(duì)于flash 空間的自編程寫命令SPM就沒有對(duì)應(yīng)的C指令了,這里不講解詳細(xì)的自編程方法,只是講解一下對(duì)flash 的讀寫函數(shù)。
直接在程序中讀取flash 空間地址數(shù)據(jù):要包含intrinsics.h頭文件
__load_program_memory(const unsigned char __flash *);//64K空間
//從指定flash 空間地址讀數(shù)據(jù)。該函數(shù)在intrinsics.h頭文件里有詳細(xì)說明。
在comp_a90.h文件有它的簡(jiǎn)化書寫_LPM(ADDR)。注意匯編指令LPM Rd ,Z中的Z是一個(gè)指針。所以用(const unsigned char __flash *)來強(qiáng)制轉(zhuǎn)換為指向flash空間地址指針。故該條宏函數(shù)的正確寫法應(yīng)該如下:
__load_program_memory((const unsigned char __flash *)ADDR);
例:
#i nclude<iom8.h>
#i nclude <intrinsics.h>
void main(void)
{PORTB=__load_program_memory((const unsigned char __flash *)0x12);
}
該條函數(shù)書寫不方便,在comp_a90.h文件有簡(jiǎn)化:
#define _LPM(ADDR) __load_program_memory (ADDR)稍微方便一點(diǎn)。改為
#define _LPM(ADDR) __load_program_memory ((const unsigned char
__flash *)ADDR)就更方便了,直接使用數(shù)據(jù)就可以了。
例:
#i nclude<iom8.h>
#i nclude<comp_a90.h>
#i nclude<intrinsics.h>
void main(void)
{
PORTB=__LPM(0x12);// 從指定flash 空間地址單元0x12中讀數(shù)據(jù)
}
__extended_load_program_memory(const unsigned char __farflash *);
//128K空間_ELPM(ADDR); //128K空間
參照上面的理解修改可以書寫更簡(jiǎn)單。
4.6.自編程函數(shù):
_SPM_GET_LOCKBITS();//讀取縮定位
_SPM_GET_FUSEBITS();//讀取熔絲位
_SPM_ERASE(Addr);//16位頁擦除
_SPM_FILLTEMP(Addr,Word);//16位頁緩沖
_SPM_PAGEWRITE(Addr;)//16位頁寫入
_SPM_24_ERASE(Addr); //24位頁擦除
_SPM_24_FILLTEMP(Addr,Data); //24位頁緩沖
_SPM_24_PAGEWRITE(Addr) //24位頁寫入
IAR for AVR 學(xué)習(xí)筆記(5)--SRAM操作
SARM數(shù)據(jù)類型的具體操作方法
SARM空間是AVR單片機(jī)最重要的部分,所有的操作必須依賴該部分來完成。變量在SARM空間的存儲(chǔ)模式有tiny ,small large 三種,也就是對(duì)應(yīng)于__tiny, __near __far三中存儲(chǔ)屬性。一旦選擇為哪種存儲(chǔ)模式,對(duì)應(yīng)的數(shù)據(jù)默認(rèn)屬性也就確定了,但可以采用__tiny, __near __far關(guān)鍵字來更改。
對(duì)于程序中的局部變量,編譯器會(huì)自動(dòng)處理的,我們也不可能加什么儲(chǔ)存屬性,但IAR提供了強(qiáng)大的外部變量定義。
5.1.定義變量在工作寄存器
IAR編譯器內(nèi)部使用了部分工作寄存器,留給用戶的只有R4-R15供12個(gè)寄存器供用戶使用,要使用工作寄存器必須在工程選項(xiàng)里打開鎖定選項(xiàng)。
例:
定義兩個(gè)變量使用工作寄存器R14,R15。
#i nclude<iom8.h>
__regvar __no_init char g @ 15;
__regvar __no_init char P @ 14;
void main(void)
{
g++;
P++;
}
在工程選項(xiàng)里c/c++ complier>code里打開要使用的寄存器R14-R15。

編譯結(jié)果就如下,看看是不是直接使用了寄存器做為數(shù)據(jù)應(yīng)用
// 4 void main(void)
main:
CFI Block cfiBlock0 Using cfiCommon0
CFI Function main
// 5 { g++;
REQUIRE ?Register_R14_is_global_regvar
REQUIRE ?Register_R15_is_global_regvar
INC R15
// 6 P++; }
INC R14
RET
注意:定義在寄存器里變量不能帶有初始值。最好不要使用超過9個(gè)寄存器變量,不然可能引起潛在的危險(xiǎn),因?yàn)榻斓臅r(shí)候沒有鎖定任何寄存器。
5.2.定義變量的絕對(duì)地址.沒有特性的變量是隨機(jī)分配的,要給變量分配地址必須加以特性修飾注意在定義地址的時(shí)候千萬不要和片內(nèi)寄存器地址重合了。
5.2.1定義沒有存儲(chǔ)特性的絕對(duì)地址變量必須加__no_init 或者const對(duì)象特性
__no_init char t @ 0x65;//定義在I/O地址以外
const char t @ 0x65;//定義只讀變量的地址
例:
#i nclude<iom8.h>
__no_init char u @ 0x65 ;
void main(void)
{u++;}
對(duì)應(yīng)匯編:
void main(void)
\ main:
{u++;}
\ 00000000 E6E5 LDI R30, 101
\ 00000002 E0F0 LDI R31,
0
\ 00000004 8100 LD R16, Z
\ 00000006 9503 INC R16
\ 00000008 8300 ST Z, R16
\ 0000000A 9508 RET
5.2.2帶存儲(chǔ)特性的關(guān)鍵字定義變量的絕對(duì)地址__io,__ext_io定義變量在i/o空間
#i nclude<iom8.h>
__io char u @ 0x65 ;
void main(void)
{u++;}
對(duì)應(yīng)匯編:
void main(void)
\ main:
{u++;}
\ 00000000 91000065 LDS R16, 101
\ 00000004 9503 INC R16
\ 00000006 93000065 STS 101, R16
\ 0000000A 9508 RET
從5.2.1和5.2.2對(duì)比,發(fā)現(xiàn)用5.2.2方法定義代碼小多了。
5.3.關(guān)鍵字volatile保證從最原始的位置讀取變量。在IAR編譯器里,除了__no_init和__root定義的變量外,其他的類型的變量都包含有volatile和__no_init特性
IAR for AVR 學(xué)習(xí)筆記(6)--中斷及相關(guān)函數(shù)操作
6.1.中斷函數(shù):
在IAR編譯器里用關(guān)鍵字來__interrupt來定義一個(gè)中斷函數(shù)。用#pragma vector來提供中斷函數(shù)的入口地址
#pragma vector=0x12//定時(shí)器0溢出中斷入口地址
__interrupt void time0(void)
{
;
}
上面的入口地址寫成#pragma
vector=TIMER0_OVF_vect更直觀,每種中斷的入口地址在頭文件里有描述。函數(shù)名稱time0可以為任意名稱。中斷函數(shù)會(huì)自動(dòng)保護(hù)局部變量,但不會(huì)保護(hù)全局變量。
6.2.內(nèi)在函數(shù)也可以稱為本征函數(shù)
編譯器自己編寫的能夠直接訪問處理器底層特征的函數(shù)。在intrinsics.h中有描述完整類型在comp_a90.h里有進(jìn)一步的簡(jiǎn)化書寫方式
6.2.1延時(shí)函數(shù),以周期為標(biāo)準(zhǔn)
__delay_cycles(unsigned long );
如果處理器頻率為1M,延時(shí)100us,如下:
__delay_cycles(100 );
當(dāng)然你也可以對(duì)該函數(shù)進(jìn)行修改:
#define CPU_F 1000000
#define delay_us (unsigned long) __delay_cycles((unsigned long )*CPU_F)
#define delay_ms (unsigned long) __delay_cycles((unsigned long )*CPU_F/1000)
6.2.2中斷指令
__disable_interrupt( );//插入CLI指令, 也可以用_CLI();也可以SREG_Bit7=0;
__enable_interrupt( );// 插入SEI指令,也可以用_SEI();也可以SREG_Bit7=1;
其實(shí)對(duì)于狀態(tài)字的置位和清零只有BSET S 和BCLR S兩條指令。像SEI不過是BSET
7;的另一個(gè)名字而已。AVR指令中還有很多類似的現(xiàn)象,如:ORI
和 SBR 指令完全一樣,號(hào)稱130多條指令的AVR其實(shí)沒有那么多指令的。
6.2.3從FLASH空間指定地址讀取數(shù)據(jù)
__extended_load_program_memory(unsigned char __farflash *);
__load_program_memory(unsigned char __flash *);
該條指令以及正確的使用方法在4.5.flash 操作宏函數(shù)里詳細(xì)講解,這里不再重復(fù)
6.2.4乘法函數(shù)
__fracdtional_multiply_signed(signed char, signed char);
__fractional_multiply_signed_with_unsigned(signed char, unsigned char);
__fractional_multiply_unsigned(unsigned char, unsigned char);
//以上為定點(diǎn)小數(shù)乘法
__multiply_signed(signed char, signed char);//有符號(hào)數(shù)乘法
__multiply_signed_with_unsigned(signed char, unsigned char);
//有符號(hào)數(shù)和無符號(hào)數(shù)乘法
__multiply_unsigned(unsigned char, unsigned char);//無符號(hào)數(shù)乘法
6.2.4 半字節(jié)交換指令
__swap_nibbles(unsigned char);
6.2.5 MCU控制指令
__no_operation();//空操作指令
_NOP();
__sleep();//休眠指令
_SLEEP();
__watchdog_reset();//看門狗清零
_WDR();
IAR for AVR 學(xué)習(xí)筆記(7)--頭文件含義
avr_macros.h里面包含了讀寫16位寄存器的簡(jiǎn)化書寫,和幾個(gè)位操作函數(shù)
comp_a90.h對(duì)大量的內(nèi)在函數(shù)做了簡(jiǎn)要書寫
ina90.h包含"inavr.h"
"comp_A90.h"文件
intrinsics.h內(nèi)在函數(shù)提供最簡(jiǎn)單的操作處理器底層特征。休眠,看門狗,FLASH函數(shù)。
iomacro.H I/O寄存器定義文件樣本。
iom8.h 包含I/O等寄存器定義
IAR for AVR 學(xué)習(xí)筆記(8)--匯編嵌入方式
嵌入?yún)R編語言
在線匯編:使用asm或者__asm,推薦使用__asm。
#i nclude<iom8.h>
void main()
{
asm("NOP \n"
"CLH \n"
"OR R16,R17 \n");
}
不過IAR提供了完全可以訪問底層的函數(shù),建議不要頻繁使用匯編
|