Файл: Programming Microcontrollers in C, 2-nd edit (Ted Van Sickle, 2001).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 15.06.2025
Просмотров: 4062
Скачиваний: 1
A Pulse Width Modulation Program |
303 |
||||
Table 6-2: GPT Interrupt Priorities And Vector Addresses |
|||||
Name |
Function |
Priority |
Vector |
||
Level |
Address |
||||
Adjusted Channel |
0 (highest) |
0xV0 |
|||
IC1 |
Input Capture 1 |
1 |
0xV1 |
||
IC2 |
Input Capture 1 |
2 |
0xV2 |
||
IC3 |
Input Capture 3 |
3 |
0xV3 |
||
OC1 |
Output Capture 1 |
4 |
0xV4 |
||
OC2 |
Output Capture 2 |
5 |
0xV5 |
||
OC3 |
Output Capture 3 |
6 |
0xV6 |
||
IC4 |
Output Capture 4 |
7 |
0xV7 |
||
IC4/OC5 |
Input Capture 4/Output Capture 5 |
8 |
0xV8 |
||
TCF |
Timer Overflow |
9 |
0xV9 |
||
PAOVF |
Pulse Accumulator Overflow |
10 |
0xVA |
||
PAIF |
Pulse Accumulator Input |
11 (lowest) |
0xVB |
||
PAB field in the ICR allows this shift. For example, if the number 6 were placed in the PAB field, then the priority of OC3 would be shifted from 6 to 0, where 0 is the highest priority of the 11 levels with the GPT. In this case, the vector for OC3 would be located at 0x40, and the vector address would be 0x80. None of the other interrupt vectors or priorities would be changed by this operation.
The remaining code of the initialization section of the above pro gram is almost the same as that found in Listing 5-5. The register and bit naming conventions used with the MC68HC16 are such that the code written for the MC68HC11 can be used directly on the MC68HC16. There is one change. In the MC68HC11, it was neces sary to set the DDRA7 bit to allow the output from OC1 to show up on the pin PA7. The GPT has a different output pin arrangement on the MC68HC16 and it does not require the use of the DDRA register at all.
One additional modification: A cli() instruction was used in Chapter 5 to enable the system interrupts. There is no single bit in the MC68HC16 that can be used to enable the interrupts. The 3-bit field in the condition code register named IP sets the level of inter rupt that can be acknowledged. Since there is no equivalent instruction, a macro definition of an instruction
#define cli() (“andp $ff1f \n”)
is included in the header file hc16.h. There is also a macro
#define sei() (“orp $00e0\n”)
304 Chapter 6 Large Microcontrollers
These two macros accomplish the equivalent of the same instruc tions for the MC68HC16. The cli() instruction clears the bits of the IP to zero, so that any interrupt will be acknowledged by the processor. The sei() instruction set the IP bits so that only a nonmaskable interrupt will be acknowledged. Additional macros can be written that enable the programmer to set the interrupt level any where between 1 and 7 if needed.
Recall that with the MC68HC11 the two registers TFLG1 and TFLG2 were different from the usual registers in the part. To reset bits in these registers, it is necessary to write ones to the designated bits rather than zeros. On the MC68HC16, this anomaly has been corrected. On the MC68HC16, to reset bits in the TFLG1 and TFLG2 registers the pro gram must write zeros to the appropriate bits. That change shows up in two locations in the OC3_Isr routine. The much more logical
TFLG1.OC1F=OFF;
.
.
TFLG1.OC3F=OFF;
instructions are used here. Otherwise, the remainder of the interrupt ser vice routine shown in Listing 6-2 is the same as that found in Listing 5-5.
This portability is what you should expect when changing be tween the MC68HC11 and the MC68HC16 family of parts. Care has been used in the design to assure that register names and bitfield names are common between the families. Therefore, code written for the MC68HC11 should move to the MC68HC16 with little change. The need for change at all is caused by the fact that architectures of the basic machines are different.
EXERCISES
1.Modify the program shown in Figure 6-2 to allow the PWM range to vary from 1 to 0XFFF. Compile this program and test the code.
2.Write a macro that will permit the program to put an arbitrary value between 0 and 7 into the IP field of the condition code register.
Cosmic MC68HC16 Compiler 305
Cosmic MC68HC16 Compiler
The Cosmic compiler for the MC68HC16 is quite similar to the MC68HC11 compiler. Its operation is the same. Several command files are used in the course of executing a compilation, and these files will be shown here. The first file is the program that completely compiles and links the program. This file is shown below:
c -dlistcs +s +o %1.c lnkh16 < %1.lnk
hexh16 -s -o %1.hex %1.h16 pause
This command file requires as an input a file with a .c extension. For example, if you were to compile the program newpwm.c , you would enter
c:\>comp newpwm
The first line will invoke the compiler and create a listing file, a source assembly listing, and an object file named newpwm.o . The second line invokes the linker named lnkh16, and requires an input file named newpwm.lnk . The .lnk file is similar to that one dis cussed in Chapter 5, and a listing of the one for this program is shown below.
# Link command file for NEWPWM.c
+h |
# multi-segment output |
-max 0xfffff |
# maximum size |
-ps16 -pc. |
# set up banking options |
-o newpwm.h16 |
# output file name |
+text -b 0 |
# reset vectors start |
address |
|
vector.o |
# vectors |
+text -b 0x400 |
# program start address |
+data -b 0x700 |
# data start address |
crts.o |
# startup routine |
newpwm.o |
# application program |
c:/cc16/lib/libi.h16 |
# C library (if needed) |
c:/cc16/lib/libm.h16 |
# machine library |
+def __memory=__bss__ |
# symbol used by library |
306 Chapter 6 Large Microcontrollers
Here the entries are fairly well explained by the comments. Note that two additional input files are required by this link file. The vec tor table vector.o is a compiled version of the vector listing given in Listing 6-1. The crts.o object module is an assembled version of the start-up routine for this machine. Both of these routines must be written and compiled or assembled for the specific program. Oth erwise, the link command file is as discussed in Chapter 5. A version of crts.s is shown below:
;C STARTUP FOR 68HC16
;Copyright (c) 1991 by COSMIC (France)
;
.external _main, __memory
.external ._main, .__bss__
.public _exit, __stext
.psect _bss |
|
sbss: |
|
.psect _text |
|
__stext: |
|
ldk #.__bss__ |
|
tbek |
|
tbxk |
|
tbzk |
|
ldab #0fh |
; start of the i/o memory space |
tbyk |
; put it in y |
ldx #sbss |
; start of bss |
clrd |
; to be zeroed |
bra mtest |
; start loop |
bcl: |
|
std 0,x |
; clear memory |
aix #2 |
; next word |
mtest: |
|
cpx #__memory |
; end of memory ? |
blo bcl |
; no, continue |
aix #1000h |
; 4K stack |
txs |
; for instance |
jsr _main,#._main ; call application |
|
_exit: |
|
bra _exit |
; loop here if return |
Cosmic MC68HC16 Compiler 307
;
.end
In the above code, the EK, XK, and ZK registers are initialized to the value found in .__bss__ . The initial value of YK is set to 0xf. The Y register will be used by the compiler to contain an offset to all of the data contained in the control registers found in the header files. Therefore, the YK register must be set to the top memory block in the computer memory space.
Using the SCI Portion of the Queued Serial Module
The queued serial module (QSM) contains two parts. The first is a convenient serial communications interface (SCI) which provides asynchronous serial communications that is used between comput ers and other devices. The remainder of the QSM is a queued serial peripheral interface that is often used for high-speed communica tions between computers and peripheral devices. This interface is strictly synchronous.
Let’s examine an interface between the program and a terminal much like that found in Chapter 5. Here, the interface will simply read in a number from the screen and put that number into the pwm_count value for the PWM program. With this operation in place, the operator can type in a value and change the PWM on time at will. Listing 6-3 contains a program that will accomplish this end.
#include “hc16.h” #include “gpt.h” #include “sim.h” #include “qsm.h” #include “defines.h”
#define PERIOD 0x1000
#define ON_TIME |
0x0800 |
|
#define SIM_IARB |
4 |
|
#define GPT_IARB |
10 |
|
#define |
GPT_IRL |
6 |
#define |
GPT_VBA |
5 |
/* |
set the |
baud rate=fclock/32*baud_rate */ |
|
#define BAUD_SET |
(32768*512)/(32*38400) |
||
/* |
function prototypes */ |
||
@port void |
OC3_Isr(void); |
||
308Chapter 6 Large Microcontrollers
/* External variables */
WORD pwm_period=0x1000, pwm_count=0x0800,new_input=0; BYTE new_character;
main()
{
/* The initialization portion of the program */
/* initialize the SIM registers */
SYNCR.X=ON; |
/* |
set the |
system freq to 16.78 mHz */ |
SYPCR.SWE=OFF; |
/* |
disable |
the watchdog */ |
/* initialize the GPT */
GPT_MCR.IARB=GPT_IARB;/* pick an IARB for the timers */
ICR.IRL=GPT_IRL; |
/* interrupt level 6 */ |
ICR.VBA=GPT_VBA; |
/* vectors start at 0x40 */ |
OC1M.OC1M3=ON; |
/* sent OC1 out to pin */ |
OC1M.OC1M5=ON; |
/* couple OC1 to OC3 */ |
TMSK1.OC3I=ON; |
/* enable the OC3 interrupt */ |
OC1D.OC1D5=ON; |
/* turn on OC3 when OC1 occurs */ |
TCTL1.OL3=ON; |
/* toggle OC3 when OC3 occurs */ |
TOC1=TCNT+pwm_period; |
/* set OC1 to the period */ |
|
TOC3=TOC1+pwm_count; |
/* set OC3 time on */ |
|
/* initialize the SCI |
*/ |
|
SCCR0.SCBR=BAUD_SET; |
/* set baud rate to 9600 */ |
|
SCCR2.TE=ON; |
/* enable the transmit and */ |
|
SCCR2.RE=ON; |
/* receiver of the SCI */ |
|
cli(); |
/* enable the system interrupts */ |
|
/* the applications portion of the program */
FOREVER
{
if (SCSR.RDRF==ON) /* read in data if it is there */
{
new_character=SCDR; /* get new byte, reset RDRF */ while(SCSR.TDRE==OFF) /* wait until transmit
buffer empty */
SCDR=new_character; /* send out byte and reset TDRE */ /* got an input, process it */ if(new_character>=’0'&&new_character<=’9')
new_input=10*new_input+new_character-’0'; else if(new_character==’\r’)
{
/* reject any number out of range */
Cosmic MC68HC16 Compiler 309
/* and start over again |
*/ |
|
if(new_input>=1 && new_input<=4048) |
||
pwm_count=new_input; |
||
new_input=0; |
||
} |
||
else |
||
new_input=0; |
/*reject |
everything else*/ |
}
}
}
/* The asynchronous service portion of the program */
@port void OC3_Isr( void) /* the PWM isr */
{
TFLG1.OC1F=OFF; |
/* reset OC1 interrupt flag */ |
if(OC1D.OC1D3==ON) |
/* toggle OC1D3 */ |
OC1D.OC1D3=OFF; |
|
else |
|
OC1D.OC1D3=ON; |
|
TFLG1.OC3F=OFF; |
/* reset OC3 interrupt flag */ |
TOC1+=pwm_period; |
|
TOC3=TOC1+pwm_count; |
}
Listing 6-3: PWM System With Keyboard Input
The qsm.h header file is included to add all of the register and defines needed for the operation of the SCI. We are going to place the operation of the SCI into the applications portion of the pro gram. Implementation of the SCI requires that a baud rate be selected and the transmit enable along with the receive enable bits be set in the serial communications control register number 2. The baud rate is set to 38400 by placing a properly calculated value into the SCBR field of SCCR0. With these lines of code, the serial communications interface is set up and ready to work.
The code inside the application portion of the program is essen tially identical to that found in Chapter 6. The only difference is that the variable names are changed to be more compliant with this appli cation. Here is another interesting case where the code written for the MC68HC11 will move directly to the MC68HC16 with minimal change.
310 Chapter 6 Large Microcontrollers
This program is a minimum SCI system. The SCI portion of this chip has comprehensive capabilities that are not exploited in the program above. These capabilities and error-checking devices are all available on the chip, and their access anduse is explained in detail in the QSM Reference Manual. Access of the various capabilities is exactly the same as was shown above in this program.
Periodic Interrupt
To make the problem a little more interesting, let’s add another load to the machine by making use of the periodic interrupt capabil ity provided in the SIM to create an interrupt. With this interrupt, we will build a time-of-day clock similar to that developed in Chapter 4. In this case you will see that the applications code developed for the MC68HC05 will work fine for the MC68HC16. Of course, the ini tialization code and the interrupt service routine will be completely different for the MC68HC16. This additional code will be put right into the program listed in Listing 6-3. It is asserted that there will be no adverse interactions between the various sections of the code.
#include “hc16z1.h” #include “gpt.h” #include “sim.h” #include “qsm.h” #include “defines.h”
#define PERIOD 0x1000
#define ON_TIME |
0x0800 |
#define SIM_IARB |
4 |
#define PIC_PIRQL |
6 |
#define PIC_PIV |
0X38 |
#define PIT_PITM |
16 |
#define GPT_IARB |
10 |
#define GPT_IRL |
6 |
#define GPT_VBA |
5 |
/* set the baud rate=fclock/32*baud_rate */
#define BAUD_SET |
(32768*512)/(32*38400) |
#define TIME_COUNT |
1000 |
#define MAX_MIN |
59 |
#define MAX_HOURS |
12 |
#define MIN_HOURS |
1 |
#define NO_WAIT |
0 |
#define OC2_OFFSET |
5 |
#define MAX_SEC |
59 |