📄 chapter6.htm
字号:
;
}
void printd(unsigned long x)
{
if(x/10)
printd(x/10);
putch(x%10+'0');
}
/* This routine returns the value to be placed in SCCR0A.BR to
make the baud rate match that measured by an input capture.
The measured value may not match the book value exactly. */
WORD get_baud(BYTE number, Timer *t3)
{
WORD start_time;
Delay *d;
Semaphore *s;
Timer1 *t;
s=semaphore_();
t=timer1_(number, /* Build input capture--number */
FALLING, /* capture falling edge */
NO); /* no interrupt */
while(!get_status(t))
; /* wait until an event occurs */
start_time=capture_time(t); /* get event time immediately */
new_edge(t,RISING); /* set the sensitivity to rising edge */
d=delay_(t3,s,11); /* t3 must be 1 ms timer to delay 11 ms */
wait_for_semaphore(s); /* wait out the delay */
start_time=capture_time(t)-start_time;
timer1__(t); /* get rid of this timer */
semaphore__(s); /* don't need semaphore any more */
return start_time%72>36?start_time/72+1: start_time/72;
}
<h4> Listing 6.6 Baud Rate Measuring Program (end )</h4>
</code></pre>
<h3><a name="internal_pulse_width_modulator">Internal Pulse Width Modulators</a></h3>
<p> In Chapter 5 we developed a pulse width modulation system that made use of two
input capture subsystems. One input capture was used to set the period of the signal and
the other controlled the on-time. This scheme can be used effeciently and it offers some
flexibility beyond that available from the two built-in pulse width modulators, PWM,
found in the <a href="appendxb.htm#gpt_h">GPT</a>. Specifically, these two PWMs are both eight-bit devices and the
PWM developed in Chapter 5 provided at lease 15 bit accuracy and resolution if needed.
On the other hand, the Chapter 5 PWM was very slow and the internal PWMs can run
considerably faster. But, this value is also flexible because a prescaler can be applied to
the PWM counter that will allow very precise PWM rates down to as slow as 4 Hz.
<p> This PWM system performs the same type of operation as that described in
Chapter 5. There is one major difference however; these two different approaches use
completely different internal portions of the microcontroller. Therefore, if we should
decide to make this PWM system inherit the attributes and methods of the system
described in Chapter 5, we would be causing peripheral components to be tied up that
would never be used. For example, the Chapter 5 system uses Output Compare 1 timer
and another timer specified by the programmer. This system does not employ any timer
functions other than the built-in PWM subsystems.
<p>The internal pwm systems are driven by the system clock through the PWM
Prescaler. There are three bits in the <a href="appendxb.htm#pwmc">PWMC</a>,
<a href="appendxb.htm#pwmcbits">PWM Control</a> register, that control the
level of the prescaler, and there is also in the same register a pair of bits called SFA and
SFB. These bits set the speed mode of the pwm to either slow or fast. The table shown
below contains a summary of the operation of the prescaler along with the slow/fast bits
for each of the pwm devices. There is only one prescaler for both pwms, so the two
pwms must run at the same basic clock speed. However, the slow/fast bit can be set for
each individual pwm.
<table>
<th>PPR[2:0] <th>Prescaler Tap <th>Fast Mode <th>Slow Mode<tr>
<td>0 <td>Div 2=8.39 MHz <td>32.8 kHz <td>256 Hz<tr>
<td>1 <td>Div 4=4.19 MHz <td>16.4 kHz <td>128 Hz<tr>
<td>10 <td>Div 8=2.10 MHz <td>8.19 kHz <td>64.0 Hz<tr>
<td>11 <td>Div 16=1.08 Mhz <td>4.09 kHz <td>32.0 Hz<tr>
<td>100 <td>Div 32=524 kHz <td>2.05 kHz <td>16.0 Hz<tr>
<td>101 <td>Div 64=262 kHz <td>1.02 kHz <td>8.0 Hz<tr>
<td>110 <td>Div 128=131 kHz <td>512 Hz <td>4.0 Hz<tr>
<td>111 <td>PCLK <td>PCLK/256 <td>PCLK/32768<tr>
</table>
<h4> Table 6.2 PWM Frequency Range Using 16.78 MHz System Clock</h4>
<p>
The header file, shown below, has some new items for a heade file. The first, is
the enumeration of some values to be used is labled static. The mnemonics A and B can
be used in this program, and any file where pwmi.h is included, but these names are
hidden from the rest of the program. Several times a bit-field definition contained within
a general header file is not quite that needed for a specific program. In this case, the
register PWMC is defined as a type Register, sixteen individual bits, in the header file
gpt.h. In this case it will make the code simpler if a bit-field that is three bits wide and
contains bits 9 through 11 in this memory location were available. Shown below is an
example of how such a modification is made. A structure that has the desired bit-field
arrangement is typedefed and then the desired address is cast onto a pointer to this new
type. Then, in the program, this new pointer can be used the same as the one defined in
the header file.
<pre><code>
#ifndef PWMI_H
#define PWMI_H
#include <hc16y1.h>
#include <defines.h>
#include <gpt.h>
#include <timer.h>
static enum {A,B};
typedef struct
{
unsigned PWM_NULL0 : 9;
unsigned PR02 :3;
unsigned PWM_NULL1 : 4;
} Pwmcspec;
#define PWMCSPEC (*(@far Pwmcspec*)(GPT_Register+0x24))
#define PWMI_CLASS \
ERROR_HANDLER \
WORD time_on; \
BYTE channel;
typedef struct
{
PWMI_CLASS
} Pwmi;
#define ON_TIME(a,b) ((a)->channel==A)?(PWMA.PWA=(b)) : (PWMB.PWB=(b))
Pwmi *pwmi_(BYTE channel,BYTE time_on,
BYTE prescale,Boolean speed);
void pwmi__(Pwmi *);
#endif
<h4> Listing 6.7 Internal PWM Object Header File</h4>
</code></pre><p>
The remainder of this header file is about the same as usual. The parameter
on_time in the object must be set by the program. Therefore, a macro function to set the
proper value in the object is included. The parameter, a, above s a pointer to an instance
of the specific pwmi to be changed, and b is the new value for the on_time.
<p> The warning shown in the listing below bears mentioning again. Each PWM
within the system is turned on and running whenever an object that contains it is
instantiated. If more than one instance of the PWM were created, the hardware would
have no mechanism for sorting out which values to use. The tests upon entering the
constructor returns an error to the calling program when an improper PWM is
instantiated. You should note that this error is a program error not a system error.
Therefore, the error handler will not be needed to take care of this type of error. A
simple return to the calling program with an error flag set is superior to our using the
error handler in cases such as these. The calling program can test the pointer that is
returned by the constructor, and if there is an error, the pointer will have a NULL value.
<p> The remainder of this constructor follows the usual approach for the creation of
an object. A Pwmi is derived from the error_handler class. An instance of the error
handler is created when the variable temp is defined, and this variable is initialized by the
call to the error constructor following the initial tests to determine if there is a calling
error. It is important that the instance of error be created after these tests because if it
were called prior to the tests, program control would be returned to the calling program
with an unused error handler object that would never be destroyed.
<pre><code>
#include <pwmi.h>
/* WARNING Only one pwm per channel can be instantiated
from this class at a time. The system has two channels.
Also, the prescaller must have the same value for both. */
static Boolean ach,bch;
Pwmi *pwmi_(BYTE channel,BYTE time_on ,
BYTE prescale,Boolean speed)
{
Pwmi *this;
Error_handler *temp;
if(channel==A && ach==ON)
return NULL;
if(channel==B && bch==ON)
return NULL;
temp=error_();
this=(Pwmi*) malloc(sizeof(Pwmi));
if(this==NULL)
error_handler(temp,TYPE_1,PWM);
memmove(this, temp, sizeof(Error_handler));
error__(temp);
this->time_on=(WORD)time_on;
this->channel=channel;
PWMCSPEC.PR02=prescale;
switch (channel)
{
case A : PWMC.SFA=speed;
PWMC.FPWMA=0; /* normal pwm output */
PWMC.PPROUT=0; /* normal pwm output */
PWMA.PWA=time_on; /* start with correct time-on*/
ach=ON;
break;
case B : PWMC.SFB=speed;
PWMC.FPWMB=0;
PWMB.PWB=time_on;
bch=ON;
}
return this;
}
void pwmi__(Pwmi * this)
{
if(this->channel==A)
ach=OFF;
else
bch=OFF;
free(this);
}
<h4> Listing 6.8 PWMI Object Implementation File</h4>
</code></pre><p>
After the object has been created, its parameters are initialized with the values
time on and channel that are passed into the constructor as arguments. The value of the
prescale is put into the bit field defined in the header file, and the switch statement
selects the proper internal channel and provides them with values.
<p> In addition to the usual job of destroying the memory allocated for the instance of
the component, the destructor in this case must also turn the static memory flag ach or
bch off whenever an instance of a PWMI is destroyed.
<p> A very simple test program follows. This program implements both of the
internal pulse width modulators. This program will implement a serial port and read data
from this port toobtain the pwm value. A range of value 0 to 500 can be input into the
serial port. This value is one hundred times the voltage that will be output from the pwm
system. In an attempt to make this program simple, the passing in of data is rather
clumsy. The data are read into a buffer and the buffer contents, which is assumed to be a
series of digits, is converted into an integer. Only three characters are converted. If any
character converted is not a digit, the conversion is terminated and the value already
created is used.
The voltage value read in is converted to a range 0 to 255 where 255 corresponds to 5.0
volts and this pwm on-time value is sent to both pwm outputs.
<p>Pwma is set to high speed, and pwmb is set to slow speed. Both of these devices
are set at a prescale division value of 2. Of course, they must both be set at the same
prescale value, but one can run high speed and the other low. For this demonstration, we
will run pwma at the high speed and pwmb at low speed. The clocking speeds, as found
from Table 6.2, are 8.19 kHz and 64.0 Hz respectively.
<pre><code>
#include <HC16Y1.h>
#include <scim.h>
#include <pwmi.h>
#include <serkb.h>
#include <defines.h>
#include <ctype.h>
#define SERIO_BAUD_19200 19200
#define SERIO_INT_VECTOR 0x40
#define SERIO_IARB 10
#define SERIO_INT_LEVEL 3
#define MAX_ON 0xff
io_command_block *iob1,ib1;
BYTE pszMessage[]=" ";
Pwmi *pwa, *pwb;
Serial_io *sio;
BYTE *msg;
main()
{
WORD value;
/* initialize the program */
/* initialize the SIM registers */
SYNCR.X=ON; /* double the clock speed--16.00 mHz */
SYPCR.SWE=OFF; /* disable the watchdog */
CSORBT.DSACK=0; /* use zero wait states for now */
cli(); /* enable system interrupts */
/* set up the serial communications */
sio=serkb_io_(SERIO_BAUD_19200, /* set the baud rate */
SERIO_INT_VECTOR, /* interrupt vector */
SERIO_IARB, /* iarb */
SERIO_INT_LEVEL); /* and interrupt level */
/* set up the io block */
iob1=&ib1; /* a block for inputs */
iob1->io_command=INPUT; /* iob1 is always input */
iob1->call_complete=FALSE;/* need to have no message in progress */
iob1->buffer_length=sizeof pszMessage;
pwa=pwmi_(A,0x80,2,FAST);
pwb=pwmi_(B,0x80,2,SLOW);
FOREVER
{
while(kbhit()) /* execute this code after a key is */
{ /* depressed */
int i;
putch('\r'); /* do a carriage return and */
putch('\n'); /* line feed */
iob1->buffer=pszMessage; /* must reset the buffer */
serial_io(sio,iob1);
while(!iob1->call_complete) /* read in volts */
; /* wait until data is in */
i=0;
value=0;
while(isdigit(pszMessage[i])&&i<3) /* convert to binary */
value=pszMessage[i++]-'0'+10*value;
if(value>500) /* 5 volts(*100) maximum */
break;
value=value*255/500; /* convert volts to binary */
ON_TIME(pwa,(BYTE)value); /* send data to the pwms */
ON_TIME(pwb,(BYTE)value);
}
}
}
<h4> Listing 6.9 PWMI Test Program</h4>
</code></pre><p>
Here again, we have an example of the ease of use of a software component. The
serial input/output program used in this case is the serkb_io system designed to send
messages to and receive messages from a terminal. The code needed to implement this
interface is simply the serkb_io constructor followed by the construction of a
input/output parameter block. When the actual serial port access is executed, the method
serial_io() is executed with pointers to the object and the parameter block as arguments.
<h3><a name="summary">Summary</a></h3>
This chapter contains descriptions of components that make use of the input
capture subsystem and the built in pulse width modulation system found in the General
Purpose Timer system. This timer is used on the M68HC11, the M68HC16 and the
M683XX families of components.
<hr>
<p>
<a href="copyrite.htm#copyright">Copyright</a>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -