Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1148236
  • 博文数量: 173
  • 博客积分: 4048
  • 博客等级:
  • 技术积分: 2679
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-12 18:53
文章分类

全部博文(173)

文章存档

2018年(1)

2016年(1)

2013年(1)

2012年(118)

2011年(52)

分类: 嵌入式

2012-01-31 10:14:56

#include<8051.h>
sbit at 0x90 led1;
void
main(void)
{
led1=0;
}
以上SDCC與Keil C的差異,在於sbit的用法,所以在Keil C是這樣子寫
sbit led1=P1^0;
而在SDCC是這樣子寫
sbit at 0x90 led1;

__sbit __at 0x90 led1;

我覺得SDCC的表達方式比較好,但是、、、李愷兒會這樣子寫
#define led1 P1_0
最主要是因為我知道P1_0已經在8051.h中定義了,我在這邊小小探討一下,關於SDCC的Data Types Specific。
Data Types Specific to the SDCC

The SDCC supports most ANSI-C data types. The SDCC also supports a number of extended data types (also called storage classes) to take advantage of the 8051-architecture. They are presented in the following subsections with examples.

Unlike some commercial 8051 microcontroller development tools, the SDCC is only capable of declaring Special Function Registers as both bit and byte addressable. Although supported by the 8051 assembly language, shared bit and byte addressable RAM is not supported by the SDCC. To prove this, observe the following code sample and compiled assembler code.

C source code:
union
{
unsigned char a_byte;
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;
} a_bit;
} a;

bit b;

void main(void)
{
a.a_byte = 0x05;
a.a_bit.bit6 = 1;
b = 1;

while(1); // program loop
}

Assembly listing (.rst file):

...
159 ;sdcctest.c:21: a.a_byte = 5;
160 ; genPointerSet
161 ; genNearPointerSet
162 ; genDataPointerSet
0031 75 21 05 163 mov _a,#0x05
164 ;sdcctest.c:23: a.a_bit.bit6 = 1;
165 ; genPointerSet
166 ; genNearPointerSet
0034 78 21 167 mov r0,#_a
168 ; genPackBits
0036 E6 169 mov a,@r0
0037 44 40 170 orl a,#0x40
0039 F6 171 mov @r0,a
172 ;sdcctest.c:25: b = 1;
173 ; genAssign
003A D2 00 174 setb _b
175 ;sdcctest.c:27: while(1); // program loop
...
Although the bit fields in declaration of "a" appear to be bit-addressable memory, the assembly listing (taken from the .rst file generated by SDCC) shows that the variable does not use bit addressing. In the listing do not confuse "a" and "_a". The "a" refers to the accumulator while the "_a" refers to the variable.

Note that the "Absolute Addressing" section of this appnote presents an interesting way to allocate memory so it acts as true bit-addressable memory.

near/data

李愷兒測試的結果,near是使用Internal RAM
Declaring a variable with the near or data storage class places the variable in directly addressable RAM in the 8051-core. The DS89C430/450 family of microcontrollers has 128 bytes of directly addressable memory available. This is the fastest type of memory that can be accessed by the 8051, and the assembly code generated to read or write data in this area of RAM requires a single MOV instruction.
#include "sdcc_reg420.h"

data unsigned char outPort0 = 0x4A;

void main(void)
{
P0 = outPort0;

while (1); // program loop
}
The sdcc_reg420.h definition file used in this example is given in Appendix A.

far/xdata

這邊李愷兒的測試,far是使用External RAM
Declaring a variable with the far or xdata storage class places the variable in external RAM. Although this gives the developer access to a much larger RAM space, the assembly code generated to read and write to this memory uses a MOVX instruction which requires loading the external memory address into the data pointer.

The DS89C430/450 family of microcontrollers includes a 1 kilobyte internal SRAM that can be used for variables declared with far/xdata. Note that the DME1:0 bits in the Power Management Register (PMR) must be set for internal SRAM mode before this memory can be initialized or used.

#include "sdcc_reg420.h"

xdata unsigned char ioPorts[2];

void main(void)
{
PMR |= 0x01; // Enable internal 1K SRAM

ioPorts[0] = 0x4A;
ioPorts[1] = 0x56;

P0 = ioPorts[0];
P1 = ioPorts[1];

while (1); // program loop
}

idata

idata我測試跟near/data感覺上差不多
Declaring a variable with the idata storage class places the variable in indirectly addressable memory within the 8051-core. Indirectly addressable memory is similar to directly addressable memory as there are 128-bytes available in the 8051-core (not including Special Function Registers). Accessing idata, however, requires an extra MOV command to move the RAM address into a working register.
#include "sdcc_reg420.h"

idata unsigned int port0_x2;

void main(void)
{
while (1) // program loop
{
port0_x2 = P0 * 2;
}
}

pdata

這也是直接access external RAM
The pdata storage class is used to access paged external data memory. This memory type is beyond the scope of this application note and interested readers are encouraged to review the pdata section in the SDCC documentation.

code

這就直接使用flash當成read only data,在PIC的Hi-TECH C等同於const,而SDCC用const也可以
Declaring a variable with the code storage class indicates that the variable will be placed in program memory (specifically flash memory within the DS89C430/450 microcontrollers). The variables are read-only for the SDCC, therefore use code to declare constants (such as lookup tables) in your program.
#include "sdcc_reg420.h"

code unsigned char out[10] = {0x03,0x45,0xFA,0x43,0xDD,
0x1A,0xE0,0x00,0x87,0x91};

void main(void)
{
data unsigned char i = 0;

while (1) // program loop
{
P0 = out[i++];
if (i==10)
i=0;
}
}
bit

Declaring a variable with the bit storage class places it in bit-addressable memory in the 8051-core. The 8051-core has 16 bytes of direct addressable RAM that can act as bit-addressable memory (bytes 0x20 to 0x2F), providing 128 total addressable bits. Variables of this type are efficient use of memory for flags.
#include "sdcc_reg420.h"

#define ESCAPE 0x1B

bit esc_char_flag = 0;

void main(void)
{
P1 = 0x00;

while (!esc_char_flag)
{
if (P0 == ESCAPE)
esc_char_flag = 1;
}

P1 = 0xFF;

while (1); // program loop
}
sfr

The sfr storage class defines a specific Special Function Register (SFR) in the 8051-core. The definition file presented in Appendix A defines all the SFRs in the DS89C430/450 microcontrollers using the sfr identifier.

Note that the following example defines the SFRs. Including the definition file sdcc_reg420.h was therefore not necessary.
sfr at 0x80 P0;
sfr at 0x90 P1;

void main(void)
{
P0 = 0x00;
P1 = 0xFF;

while (1); // program loop
}

sbit 這個有趣了,這容易跟sfr的位置弄混,其實這兩個的位置的定義是不一樣的,sfr是定義sfr address,而sbit是定義abit address,請參考note最後面的Keil C 對於sbit 部份說明。最後一段最經典

The sbit storage class defines a specific bit inside a bit-addressable SFR. In the 8051-core, all SFRs with an address that finishes with either a 0 or an 8 (in hex) are bit addressable.
sfr at 0x80 P0; // Port 0

sbit at 0x80 P0_0; // Port 0 bit 0
sbit at 0x81 P0_1; // Port 0 bit 1
sbit at 0x82 P0_2; // Port 0 bit 2
sbit at 0x83 P0_3; // Port 0 bit 3
sbit at 0x84 P0_4; // Port 0 bit 4
sbit at 0x85 P0_5; // Port 0 bit 5
sbit at 0x86 P0_6; // Port 0 bit 6
sbit at 0x87 P0_7; // Port 0 bit 7

void main(void)
{
P0 = 0x00; // P0 = 0x00

P0_4 = 1; // P0 = 0x10

while (1); // program loop
}
Absolute Addressing 絕對位置定義,我覺得SDCC這功能還蠻棒的,使用at。但是要小心這裡面似乎有bug,還沒有趣研究

Absolute addressing is supported by the SDCC using the at identifier. The SDCC will not, unfortunately, track variables declared at absolute addresses and may declare other variables so that they will overlap.

The following example program presents interesting potential bugs.
#include "sdcc_reg420.h"

unsigned char a = 0x4A;
unsigned int b = 0x0000;
unsigned char c[64] = {0x00};

unsigned char at 0x0010 y;
unsigned char at 0x0010 z;

void main(void)
{
for(b=0; b<64; b++)
c[b] = 0xAA;

y = 0xF1;
z = 0xF2;

a = c[5];

while (1); // program loop
}
Using the SDCC, the example compiles without any errors or any warnings, even though two variables, "y" and "z", are assigned to the same location. Next, if we were to run this program, we would expert the final assignment in the program (a = c[5]) to set "a" to 0xAA. But this is not the case. The actual value of "a" after the final assignment is 0xF2.

We can see the reason for this strange result by examining the following lines in the .map file created by SDCC that show the actual addresses used for each variable.
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
. .ABS. 0000 0000 = 0. bytes (ABS,OVR)

Value Global
-------- --------------------------------
...
0010 _y
0010 _z
...

Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
DSEG 0008 0043 = 67. bytes (REL,CON)

Value Global
-------- --------------------------------
0008 _a
0009 _b
000B _c
Note that the underscore placed at the beginning of the variable name is added by the compiler. If "c" will be located at address 0x000B and will be an array 64 bytes long, it will overlap the "y" and "z" variables at address 0x0010.

A use for absolute addressing is to simulate bit-addressable variables. In the following example, we choose to define the variable n_byte at the last byte location in bit-addressable memory. Next, we define n_bit0 to n_bit7 in the last 8 bit locations of bit-addressable memory in the 8051-core. As these overlap, the n_byte variable can be bit addressed using the n_bit0 to n_bit7 variables.
#include "sdcc_reg420.h"

data unsigned char at 0x002F n_byte;

bit at 0x78 n_bit0;
bit at 0x79 n_bit1;
bit at 0x7A n_bit2;
bit at 0x7B n_bit3;
bit at 0x7C n_bit4;
bit at 0x7D n_bit5;
bit at 0x7E n_bit6;
bit at 0x7F n_bit7;

void main(void)
{
n_byte = 0x00;
n_bit4 = 1;

P0 = n_byte; // P0 = 0x10

while (1); // program loop
}

Memory Models

The SDCC supports two memory models: small and large. When using the small memory model, the SDCC declares all variables without a storage class (i.e., data, idata, xdata, pdata, bit, code) in internal RAM. When using the large memory model, the SDCC declares all variables without a storage class in external RAM.

The small memory model is the default when compiling with the SDCC. To force the SDCC to use a particular memory model, add the following command line parameters:
sdcc --model-small sdcctest.c
or
sdcc --model-large sdcctest.c
Never combine modules or objects files compiled with different storage classes.

Interrupts in SDCC 同Keil C 的寫法

The following format should be used to define an Interrupt Service Routine (ISR):
void interrupt_identifier (void) interrupt interrupt_number using bank_number
{
...
}
The interrupt_identifier can be any valid SDCC function name. The interrupt_number is the interrupt's position within the interrupt vector table. Table 1 shows the Interrupt Numbers for every interrupt supported by the DS89C430/450 family of microcontrollers. The bank_number is an optional parameter that indicates to the SCDD which register bank to use for storing local variables in the ISR.

Table 1. Interrupt Numbers for DS89C430/450 Interrupts Service Routines

Interrupt Name Interrupt Vector Interrupt Number
External Interrupt 0 0x03 0
Timer 0 Overflow 0x0B 1
External Interrupt 1 0x13 2
Timer 1 Overflow 0x1B 3
Serial Port 0 0x23 4
Timer 2 Overflow 0x2B 5
//以上是標準8051定義的
Power Fail 0x33 6
Serial Port 1 0x3B 7
External Interrupt 2 0x43 8
External Interrupt 3 0x4B 9
External Interrupt 4 0x53 10
External Interrupt 5 0x5B 11
Watchdog Interrupt 0x63 12

The SDCC handles many details involved with programming ISRs, like saving and restoring accumulators and the data pointer to and from the stack. (This is actually done for all functions as well. Refer to the _naked keyword in the SDCC manual to disable saving these variables to the stack.) Other details are not handled by the SDCC (for good reason) and present traps to developers new to embedded programming. Many of these issues are advanced programming concepts beyond the scope of this article, but the SDCC manual as well as embedded programming textbooks can provide more insight.

The following rules should be followed when using interrupts.
Every global variable that can be written to inside an ISR and that is accessed outside the ISR must be declared as volatile. This will ensure that the optimizer does not remove instructions relating to this variable.
Disable interrupts whenever using data in a non-atomic way (i.e., accessing 16-bit/32-bit variables). Access to a variable is atomic when the processor cannot interrupt (with an ISR) storing and loading data to and from memory.
Avoid calling functions from within an ISR. If you must do this, declare the function as reentrant (see SDCC manual) which allocates all local variables in the function on the stack instead of in RAM.
Note that if your SDCC program uses ISRs located in source files other than the one that contains your main() function, the source file containing the main() function should include a function prototype for each of these ISRs.

The example below defines an ISR to handle Serial Communication Interface 1 (SCI_1) Interrupt Service Routines. The program receives a byte from the SCI_1 receiver, increments the byte by one, and transmits it continuously through the SCI_1 transmitter.
#include "sdcc_reg420.h"

volatile unsigned char n = 0x4A;

void sci1ISR (void) interrupt 7
{
if (RI_1)
{
n = SBUF1+1; // Save Rx byte
RI_1 = 0; // Reset SCI_1 Rx interrupt flag
}
else if (TI_1)
{
SBUF1 = n; // Load byte to Tx
TI_1 = 0; // Reset SCI_1 Tx interrupt flag
}
}

void main(void)
{
// 1. Init Serial Port
EA = 0; // Enable global interrupt mask
SCON1 = 0x50; // Set SCI_1 to 8N1, Rx enabled
TMOD |= 0x20; // Set Timer 1 as Mode 2
TH1 = 0xDD; // Set SCI_1 for 2400 baud
TR1 = 1; // Enable Timer 1
ES1 = 1; // Enable interrupts for SCI_1
EA = 1; // Disable global interrupt mask

// 2. Initiate SCI_1 Tx
SBUF1 = n;

// 3. Program loop...
while (1);
}
Inline Assembly

Inline assembly is fully supported by the SDCC. To use this feature, enclose the assembly code between the _asm and _endasm identifiers. Note that inline assembly code can also access C variables by prefixing the variable name with an underscore character. The following example uses inline assembly to perform nop instructions (used to waste a clock cycle within the microcontroller) and then increment the variable "a" by one.
#include "sdcc_reg420.h"

unsigned char a;

void main(void)
{
// program loop...
while (1)
{

a = P0;

_asm
nop
nop
nop
inc _a
_endasm;

P1 = a;
}
}
The SDCC is also capable of interfacing C and assembly functions. This is an advanced topic; refer to the SDCC manual for details.

以下是摘自Keil C 對於sbit 部份的說明。最後一段最經典
sbit

The sbit type defines a bit within a special function register (SFR). It is used in one of the following ways:

sbit name = sfr-name ^ bit-position;
sbit name = sfr-address ^ bit-position;
sbit name = sbit-address;
Where
name is the name of the SFR bit.
sfr-name is the name of a previously-defined SFR.
bit-position is the position of the bit within the SFR.
sfr-address is the address of an SFR.
sbit-address is the address of the SFR bit.
With typical 8051 applications, it is often necessary to access individual bits within an SFR. The sbit type provides access to bit-addressable SFRs and other bit-addressable objects. For example:

sbit EA = 0xAF;
This declaration defines EA as the SFR bit at address 0xAF. On the 8051, this is the enable all bit in the interrupt enable register.

Note
Storage of objects accessed using sbit is assumed to be little endian (LSB first). This is the storage format of the sfr16 type but it is opposite to the storage of int and long data types. Care must be taken when using sbit to access bits within standard data types.
Any symbolic name can be used in an sbit declaration. The expression to the right of the equal sign ('=') specifies an absolute bit address for the symbolic name. There are three variants for specifying the address:

Variant 1

sbit name = sfr-name ^ bit-position;
The previously declared SFR (sfr-name) is the base address for the sbit. It must be evenly divisible by 8. The bit-position (which must be a number from 0-7) follows the carat symbol ('^') and specifies the bit position to access. For example:

sfr PSW = 0xD0;
sfr IE = 0xA8;

sbit OV = PSW^2;
sbit CY = PSW^7;
sbit EA = IE^7;
Variant 2

sbit name = sfr-address ^ bit-position;
A character constant (sfr-address) specifies the base address for the sbit. It must be evenly divisible by 8. The bit-position (which must be a number from 0-7) follows the carat symbol ('^') and specifies the bit position to access. For example:

sbit OV = 0xD0^2;
sbit CY = 0xD0^7;
sbit EA = 0xA8^7;
Variant 3

sbit name = sbit-address;
A character constant (sbit-address) specifies the address of the sbit. It must be a value from 0x80-0xFF. For example:

sbit OV = 0xD2;
sbit CY = 0xD7;
sbit EA = 0xAF;
Note

Not all SFRs are bit-addressable. Only those SFRs whose address is evenly divisible by 8 are bit-addressable. The lower nibble of the SFR's address must be 0 or 8. For example, SFRs at 0xA8 and 0xD0 are bit-addressable, whereas SFRs at 0xC7 and 0xEB are not. To calculate an SFR bit address, add the bit position to the SFR byte address. So, to access bit 6 in the SFR at 0xC8, the SFR bit address would be 0xCE (0xC8 + 6).
Special function bits represent an independent declaration class that may not be interchangeable with other bit declarations or bit fields.
The sbit data type declaration may be used to access individual bits of variables declared with the bdata memory type specifier. Refer to Bit-addressable Objects for more information.
sbit variables may not be declared inside a function. They must be declared outside of the function body.
只有那些SFRs的位置可以被8除的,才是bit-addressable!!
阅读(13278) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~