ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 14.06.2025
Просмотров: 3142
Скачиваний: 0
140 10 AVR Development Board
The CODE segment starts with the interrupt vector area. In this example, only two vectors are used: the reset vector, and the vector for the interrupt for timer0 overflow. The reset vector directs the program to the initialization sequence, and the timer0 overflow vector contains a jump instruction to the associated interrupt service routine, isr_t0_ov.
INIT.ASM contains the initialization sequence, which starts by loading the stack pointer SP with the last address of the internal RAM (Ramend), then calls the initialization routines for timer0, and I/O port B.
After the initialization sequence, the program enables the interrupts, loads the software timer s_timer0 with a constant (time_s_timer0), which defines the time between the moments when port B changes its status, then enters the main loop.
This software timer is the key element of the program. Basically, s_timer0 is an 8-bit RAM variable defined in MAP.ASM, and decremented every 10 milliseconds by the interrupt service routine for timer0 overflow. If the timer is loaded with the value N, it will reach zero after a time T = N × 10 ms.
In this example, N is the constant time_s_timer, defined in MAP.ASM with the value 50, which gives a total time of 500 ms between the moments when port B is toggled. When the software timer expires, port B changes its status, then the timer is reloaded, and the program continues in an endless loop.
The resource-specific routines are placed outside the main loop in the modules TIMER.ASM and IO.ASM. TIMER.ASM contains the initialization sequence for timer0, organized as a subroutine init_timer0, and the interrupt service routine that implements the software timer.
Here is the listing of TIMER.ASM:
init_timer0:
ldi tmp1,prescaler_constant out tccr0,tmp1
ldi tmp1,ft_div mov rint,tmp1 out tcnt0,tmp1 ldi tmp1,$01 out timsk,tmp1 ret
This routine chooses the division factor for the prescaler, and the number of clocks before overflow, then enables the interrupt for timer0 overflow.
isr_t0_ov:
out |
tcnt0,rint |
in |
rsav,sreg |
push |
tmp1 |
rcall |
soft_timer |
pop |
tmp1 |
out |
sreg,rsav |
ret |
10.4 The Software |
141 |
Note how this routine saves and restores the CPU status. The register rint (an alias for r1) is preloaded with the number of clocks before tcnt0 overflows, so that tcnt0 can be reloaded as fast as possible.
soft_timer:
lds tmp1,s_timer0 tst tmp1
breq sft1 dec tmp1
sts s_timer0,tmp1
sft1:
lds tmp1,s_timer1 tst tmp1
breq ex_sft dec tmp1
sts s_timer1,tmp1
ex_sft:
ret
The routine soft_timer implements two independent software timers, s_timer0 and s_timer1. In principle, the number of distinct timers that can be implemented using this technique is limited only by the time required to execute the interrupt service routine. If a larger number of software timers is required, use the technique described in Chap. 9 for HC11 to reduce the execution time of the interrupt service routine.
Step 6. Adding a New Task to an Existing Application
The structure of the software described in the previous paragraph can be used for almost any application. Adding a new task to an existing application involves the following steps:
1.Modify MAP.ASM to define more variables if needed.
2.Write a new software module if a new resource is required. It is recommended to keep all the routines associated with specific resources in separate files (e.g. TIMER.ASM, IO.ASM, UART.ASM, ADC.ASM, etc.)
3.Modify the main program so that it includes calls to subroutines that actually execute the new task.
In the following example, the program reports the status of port B as a string of two ASCII digits, followed by CR+LF, over the asynchronous serial communication line, when the ASCII code for ‘?’ is received on the serial line. Note that port B is toggled every 500 ms, as described in the previous example.
The UART initialization routine and the communication routines are placed in a separate file UART.ASM, invoked in the main module using the “.include” directive. A separate file, LIB.ASM, is used for miscellaneous library routines – in this case hex-to-ASCII conversion routines used to prepare data for serial communication.
142 10 AVR Development Board
Here is the listing of the main module UARTMAIN.ASM:
.include ‘‘8535def.inc’’
.include ‘‘map.asm’’
.cseg
.org 0
reset:
rjmp init
.org 9 vector_t0_ov:
rjmp isr_t0_ov
init:
.include ‘‘init.asm’’ sei
ldi |
tmp1,time_s_timer0 |
sts |
s_timer0,tmp1 |
main_loop: |
|
rcall |
get_uart |
brcc |
main0 |
cpi |
tmp1,’?’ |
brne |
main0 |
rcall |
send |
main0: |
|
lds |
tmp1,s_timer0 |
tst |
tmp1 |
brne |
main_loop |
ldi |
tmp1,time_s_timer0 |
sts |
s_timer0,tmp1 |
rcall |
toggle |
rjmp |
main_loop |
,include ‘‘timer.asm’’
.include ‘‘uart.asm’’
.include ‘‘io.asm’’
.include ‘‘lib.asm’’
Note the two new subroutine calls included in the main loop: get_uart, and send. Get_uart checks if a character is available in the receiver’s data register, reads the character in tmp1, and sets the carry bit to inform the main program. When no
character is available, get_uart returns carry = 0.
get_uart:
clc |
||
sbis |
usr,rxc |
;check rxc status bit |
ret |
||
in |
tmp1,udr |
;get character received |
sec |
;set carry |
|
ret |
;and return |
10.4 The Software |
143 |
Send prepares and sends over the communication line a string comprising two ASCII digits corresponding to the hexadecimal value of each nibble of port B, plus CR and LF.
send:
rcall |
hex_asc |
;convert tmp1 to ASCII |
rcall |
put_uartw |
;send tmp1 |
mov |
tmp1,tmp2 |
;next character in tmp2 |
rcall |
put_uartw |
;send next character |
ldi |
tmp1,$0D |
;CR |
rcall |
put_uartw |
|
ldi |
tmp1,$0A |
;LF |
rcall |
put_uartw |
|
ret |
Put_uartw waits for the status bit UDRE to be set, then writes the content of tmp1 to UDR. It does not check for valid ASCII characters before sending.
put_uartw:
sbis |
usr,udre |
;check if |
TX |
|
;register |
empty |
|||
rjmp |
put_uartw |
;wait |
until ready to send |
|
out |
udr,tmp1 |
;send |
the byte |
|
ret |
||||
144 10 AVR Development Board
10.5 Exercises
SX 10.1
Use two software timers to make the upper and lower nibble of port B toggle at different time intervals.
Solution
The two software timers s_timer0 and s_timer1 described in the previous paragraphs must be loaded with different constants to obtain different time intervals for toggling the lines of port B. Here is how LEDMAIN.ASM should be modified for this:
init: |
||
.include ‘‘init.asm’’ |
||
sei |
||
ldi |
tmp1,time_s_timer0 |
|
sts |
s_timer0,tmp1 |
;start s_timer0 |
ldi |
tmp1,time_s_timer1 |
|
sts |
s_timer1,tmp1 |
;start s_timer1 |
main_loop: |
||
lds |
tmp1,s_timer0 |
|
tst |
tmp1 |
|
brne |
main1 |
|
ldi |
tmp1,time_s_timer0 ;restart s_timer0 |
|
sts |
s_timer0,tmp1 |
|
rcall |
toggle1 |
;act on port |
main1: |
||
lds |
tmp1,s_timer1 |
;check s_timer1 |
tst |
tmp1 |
|
brne |
main_loop |
|
ldi |
tmp1,time_s_timer1 ;restart s_timer1 |
|
sts |
s_timer1,tmp1 |
|
rcall |
toggle2 |
;act on port |
rjmp |
main_loop |
|
Each of the subroutines toggle1 and toggle2 must affect only one nibble of port B, leaving the other nibble unchanged:
toggle1:
in |
tmp1,portb |
;read port |
mov |
tmp2,tmp1 |
;save it to tmp2 |
andi |
tmp2,$0F |
;mask lower nibble |
com |
tmp1 |
|
andi |
tmp1,$F0 |
;mask upper nibble |
or |
tmp1,tmp2 |
;recompose |
out |
portb,tmp1 |
;write new value |
ret |
;to the port |
11
8051 Development Board
11.1 In this Chapter
This chapter contains the description of a simple development board for the study of the 8051 family of microcontrollers.. Unlike the development boards dedicated to the HC11 and AVR families, presented in the previous chapters, this project allows the user to load and execute programs in an external RAM area, addressed to be visible both in the program memory and data memory address space.
11.2 Hardware
The schematic of the board is presented in Fig. 11.1, 11.2, and 11.3. Figure 11.1 shows the microcontroller IC10, the bus demultiplexer IC7, the RS232 interface IC12, the RESET and clock circuits, and the ISP connector SV1.
Note the presence of the two NAND gates IC6C and IC6D, which implement the logic function AND between the signals RD\ (Read) and PSEN\ (Program Store Enable), both active LOW, and generate the signal RDPSEN. RDPSEN is active LOW when either RD\ or PSEN\ is LOW. Connecting this signal to the RD\ input of an external RAM circuit allows the use of this RAM to store program as well as data.
The microcontroller can be any of 8032, 8051, 8052, AT89C51, AT89C52, etc. in a DIP40 package. The input EA\ (External Access) of the MCU is connected to the jumper JP1 to allow the use of the internal ROM, if this is available. Connect the jumper so that EA\ = 1 to use the internal ROM. When the external ROM is used, EA\ must be connected to GND.
The clock circuit comprises the crystal Q1 (14.74 MHz) and the capacitors C6, C7 (22 pF). C5 (10 µF) and R4 (10 K) implement the RESET circuit. The pushbutton S1 is provided to allow manual reset of the circuit.
The latch SN74HC573 (IC7), controlled by the signal ALE (Address Latch Enable), is used to demultiplex the external data bus, by storing the lower half (A0–A&) of the address bus.
146 |
11 |
8051 Development Board |
||||||||||||||
C10 |
IC12 |
|||||||||||||||
1 C1+ |
C11 |
VCC |
||||||||||||||
3 C1- |
V+ 2 |
|||||||||||||||
C9 |
V- |
6 |
GND |
|||||||||||||
4 C2+ |
||||||||||||||||
C8 |
SV2 2 |
|||||||||||||||
TX |
5 C2- |
14 |
1 |
|||||||||||||
11 |
T1IN T1OUT |
3 |
4 |
|||||||||||||
5 |
6 |
|||||||||||||||
12 R1OUT R1IN 13 |
7 |
8 |
||||||||||||||
J1 |
9 |
10 |
||||||||||||||
8051 |
MAX232 |
|||||||||||||||
15 |
16 WR\ |
|||||||||||||||
LSP 4 |
P35-T1 P36-WR |
IC6D |
IC6C |
|||||||||||||
14 |
||||||||||||||||
6 |
13 |
P34-T0 |
17 RD\ |
12 |
11 |
9 |
8 RDPSEN |
|||||||||
3 |
12 |
P33-INT1 P37-RD |
||||||||||||||
5 |
11 |
P32-INT0 |
PSEN |
29 PSEN 13 |
10 |
|||||||||||
GND |
SV1 |
P31-TXD |
||||||||||||||
10 |
74HC00 |
DATA BUS |
||||||||||||||
10 |
9 |
MISO |
P30-RXD |
ALE |
30 ALE |
|||||||||||
8 |
7 |
SCK |
8 |
IC7 |
||||||||||||
6 |
5 |
LD |
P17 |
39 D0 |
19 A0 |
|||||||||||
4 |
3 |
7 |
P00-AD0 |
D0 2 |
1D |
1Q |
||||||||||
2 |
1 |
MOSI |
6 |
P16 |
38 D1 |
D1 3 |
18 A1 |
|||||||||
MRST |
5 |
P15 |
P01-AD1 |
37 D2 |
D2 4 |
2D |
2Q |
17 A2 |
||||||||
4 |
P14 |
P02-AD2 |
36 D3 |
D3 5 |
3D |
3Q |
16 A3 |
|||||||||
VCC |
LSP 7 |
3 |
P13 |
P03-AD3 |
35 D4 |
D4 6 |
4D |
4Q |
15 A4 |
|||||||
2 |
P12 |
P04-AD4 |
34 D5 |
D5 7 |
5D |
5Q |
14 A5 |
|||||||||
R4 |
2 |
1 |
P11 |
P05-AD5 |
33 D6 |
D6 8 |
6D |
6Q |
13 A6 |
|||||||
1 |
P10 |
P06-AD6 |
32 D7 |
D7 9 |
7D |
7Q |
12 A7 |
|||||||||
RST |
9 |
RST |
P07-AD7 |
8D |
8Q |
|||||||||||
ALE 11 |
||||||||||||||||
JP2 |
C |
|||||||||||||||
VCC |
31 |
EA |
21 A8 |
|||||||||||||
20 |
P20-A8 |
1 |
0C |
LOW ADDRESS BUS |
||||||||||||
GND |
22 A9 |
|||||||||||||||
C5 |
40 |
P21-A9 |
23 A10 |
74HC573 |
||||||||||||
S1 |
18 |
VCC |
P22-A10 |
24 A11 |
GND |
|||||||||||
XTAL2 |
P23-A11 |
25 A12 |
||||||||||||||
C6 |
P24-A12 |
26 A13 |
||||||||||||||
Q1 |
P25-A13 |
27 A14 |
||||||||||||||
P26-A14 |
28 A15 |
|||||||||||||||
19 |
XTAL1 |
P27-A15 |
HIGH ADDRESS BUS |
|||||||||||||
JP1 |
||||||||||||||||
GND C7 |
IC10 |
|||||||||||||||
Fig. 11.1. MCU, bus demultiplexer, RESET, clock, and RS232
The ISP (In System Programming) connector SV1 has been included to allow the use of microcontrollers like AT89LS51, AT89S52 that are provided with this feature. In this case, the jumper JP2 must be connected to bring the signal RST to SV1 pin 5.
The memory circuits and the address decoder are presented in Fig. 11.2. IC5 (AT28C64) is an 8-kilobytes EEPROM, having the chip select input CS\ connected to the signal CS0000, generated by the address decoder IC9 (7445), and the output enable input OE driven by the signal PSEN, generated by the MCU.
LOW ADDRESS BUS |
DATA BUS |
||||||||||
IC5 |
|||||||||||
A0 10 |
11 D0 |
IC2 |
6264 |
||||||||
A0 |
I/O0 |
A0 10 |
|||||||||
A1 |
9 |
A1 |
I/O1 |
12 D1 |
A0 |
I/O0 |
11 D0 |
||||
A2 |
8 |
A2 |
I/O2 |
13 D2 |
A1 |
9 |
A1 |
I/O1 |
12 D1 |
||
A3 |
7 |
A3 |
I/O3 |
15 D3 |
A2 |
8 |
A2 |
I/O2 |
13 D2 |
||
A4 |
6 |
A4 |
I/O4 |
16 D4 |
A3 |
7 |
A3 |
I/O3 |
15 D3 |
||
A5 |
5 |
A5 |
I/O5 |
17 D5 |
A4 |
6 |
A4 |
I/O4 |
16 D4 |
||
A6 |
4 |
A6 |
I/O6 |
18 D6 |
A5 |
5 |
A5 |
I/O5 |
17 D5 |
||
A7 |
3 |
A7 |
I/O7 |
19 D7 |
A6 |
4 |
A6 |
I/O6 |
18 D6 |
||
A8 25 |
A8 |
A7 |
3 |
A7 |
I/O7 |
19 D7 |
|||||
A9 24 |
A9 |
A8 25 |
A8 |
D0 |
VCC |
||||||
A10 21 |
A10 |
A9 24 |
A9 |
||||||||
A11 23 |
A11 |
A10 21 |
A10 |
D1 |
|||||||
A12 |
2 |
A12 |
A11 23 |
A11 |
D2 |
R6 |
|||||
CS0000 20 |
CE\ |
A12 |
2 |
A12 |
D3 |
||||||
CS2000 20 |
CE\ |
D4 |
|||||||||
PSEN 22 |
OE\ |
D5 |
|||||||||
VCC |
27 |
WE\ |
RDPSEN 22 |
OE\ |
D6 |
||||||
AT28C64 |
WR\ |
27 |
WE\ |
D7 |
VCC |
||||||
A13 15 |
A |
O0 |
1 |
CS0000 |
|||||||
A14 14 |
B |
O1 |
2 |
CS2000 |
R3 |
||||||
A15 13 |
C |
O2 |
3 |
CS4000 |
|||||||
HIGH ADDRESS BUS |
12 |
D |
O3 |
4 |
CS6000 |
||||||
O4 |
5 |
CS8000 |
|||||||||
GND |
O5 |
6 |
CSA000 |
||||||||
O6 |
7 |
CSC000 |
|||||||||
O7 |
9 |
CSE000 |
|||||||||
IC9 |
7445 |
||||||||||
Fig. 11.2. External memory and address decoder