目次
前
次
PWM制御
PWM(Pulse Width Modulation)は、DCモータの回転速度を
可変にするために、使われます。
CCS社のCコンパイラを使って、PWMの波形生成を考えます。
PWMは、1周期の時間間隔の中でHがどれだけ続く
のかを、Duty比というパラメータで表現します。
Duty比をデジタル値で与えたいので、0〜99の
整数で指定できるようにしました。
時間差を利用すれば、周期を生成できます。
タイマー割込みで、0〜99までを生成し
与えたデジタルのDuty比と比較し、出力
する論理値を確定させます。
タイマー割込みが発生するたびに、カウンタを+1して
100になると、0に戻します。図では、左から右に大きく
なる傾斜がカウンタに相当します。
Duty比は可変にしますが、図では赤線の上下移動が可変になります。
タイマー割込みの発生をフラグで通知して
カウンタをインクリメントし、Duty比から
出力論理値を確定するコードを記述します。
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* impress */
if ( dflag == ON ) {
if ( pcnt < dcnt ) { a_port |= 0x01 ; }
else { a_port &= ~0x01 ; }
} else {
a_port &= ~0x01 ;
}
/* increment */
pcnt++ ;
if ( pcnt == 100 ) {
/* clear */
pcnt = 0 ;
/* update duty ratio */
dcntx = dcnt ;
}
}
Duty比は、変数dcnt、dcntxで管理します。
変数を2つ用意するのは、シリアルインタフェースで
Duty比を設定したときに、1周期の間に回転数が変化
しないようにするため。
コマンドを考えます。
- ? help
- E enable rotation
- D disable rotation
- P set duty
- p show duty
コマンドを決めれば、コマンドインタプリタは
定義できます。
if ( sflag == ON ) {
/* clear flag */
sflag = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* judge */
if ( cmd == '?' ) {
puts("? help");
puts("E enable");
puts("D disable");
puts("P set duty");
puts("p show duty");
}
if ( cmd == 'E' ) { dflag = ON ; }
if ( cmd == 'D' ) { dflag = OFF ; }
if ( cmd == 'P' ) {
dcnt = get_hex( *(sbuf+1) );
dcnt *= 10 ;
dcnt += get_hex( *(sbuf+2) );
}
if ( cmd == 'p' ) {
tmp = dcnt ;
putc( '0' + (tmp / 10) ) ;
putc( '0' + (tmp % 10) ) ;
crlf();
}
}
受信割込みは、プラグマを利用し定義します。
#int_rda
void echo_back(void)
{
UBYTE ch ;
/* get 1 charactor */
ch = rcreg ;
/* store */
*(sbuf + sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == CR ) {
sindex = 0 ;
sflag = ON ;
}
}
もうひとつの割込みである、タイマー割込みは
タイマー0を利用して定義します。
#int_rtcc
void rtcc_handler(void)
{
/* update */
set_timer0( 6 ) ;
/* set flag */
tflag = ON ;
}
PICは割込みハンドラのエントリーアドレスは
0x04で固定なので、Cコンパイラが、プラグマ
を見ながら、指定された割込み処理を並べます。
タイマー0は、1msごとに割込みを発生させます。
PWM波形出力は、RA0からとします。
仕様を決めれば、初期化部分を作成できます。
void user_initialize(void)
{
/* disable A/D converter */
setup_adc_ports( NO_ANALOGS );
/* set directions */
set_tris_a( 0x00 ) ; /* all outputs */
set_tris_b( 0xff ) ; /* all inputs */
set_tris_c( 0x80 ) ;
/* initialize port values */
a_port = 0xff ; /* */
b_port = 0x00 ; /* */
c_port = 0xdf ; /* */
/* initialize pointer */
sindex = 0 ;
/* initialize counter */
pcnt = 0 ;
dcnt = 0 ;
dcntx = 0 ;
/* clear flags */
sflag = OFF ;
tflag = OFF ;
dflag = OFF ;
/* initialize timer 0 */
setup_counters( RTCC_INTERNAL , RTCC_DIV_8 );
set_timer0( 6 );
/* enable interrupt */
enable_interrupts( INT_RTCC );
enable_interrupts( INT_RDA );
enable_interrupts( GLOBAL );
}
初期化処理の最後に、割込みが発生するように
設定しておきます。
ソースコードは、以下。
#include <16f873.H>
/* */
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
/* */
#define CR 0x0d
#define LF 0x0a
/* redefine register name */
#byte a_port = 0x05
#byte b_port = 0x06
#byte c_port = 0x07
#byte rcreg = 0x1a
#fuses XT,WDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
/* redefine data types */
typedef unsigned int UBYTE ;
typedef unsigned long UWORD ;
typedef signed int SBYTE ;
/* global variables */
UBYTE sbuf[8];
UBYTE sindex;
UBYTE sflag ;
UBYTE tflag ;
UBYTE cmd ;
UBYTE pcnt ;
UBYTE dcnt ;
UBYTE dcntx ;
UBYTE dflag ;
#define NO 0
#define YES 1
#define OFF 0
#define ON 1
#define MASK0F 0x0f
/* new line */
void crlf(void)
{
putc( LF );
putc( CR );
}
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
UBYTE get_hex(UBYTE x);
/* receive interrupt */
#int_rda
void echo_back(void)
{
UBYTE ch ;
/* get 1 charactor */
ch = rcreg ;
/* store */
*( sbuf + sindex ) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == CR ) {
sindex = 0 ;
sflag = ON ;
}
}
/* timer0 interrupt */
#INT_RTCC
void rtcc_handler(void)
{
/* update */
set_timer0( 6 ) ;
/* set flag */
tflag = ON ;
}
void main(void)
{
UBYTE tmp ;
/* initialize */
user_initialize();
puts("Hello !");
/* loop */
while ( ON ) {
/* receive handling */
if ( sflag == ON ) {
/* clear flag */
sflag = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* judge */
if ( cmd == '?' ) {
puts("? help");
puts("E enable");
puts("D disable");
puts("P set duty");
puts("p show duty");
}
if ( cmd == 'E' ) { dflag = ON ; }
if ( cmd == 'D' ) { dflag = OFF ; }
if ( cmd == 'P' ) {
dcnt = get_hex( *(sbuf+1) );
dcnt *= 10 ;
dcnt += get_hex( *(sbuf+2) );
}
if ( cmd == 'p' ) {
tmp = dcnt ;
putc( '0' + (tmp / 10) ) ;
putc( '0' + (tmp % 10) ) ;
crlf();
}
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* impress */
if ( dflag == ON ) {
if ( pcnt < dcnt ) { a_port |= 0x01 ; }
else { a_port &= ~0x01 ; }
} else {
a_port &= ~0x01 ;
}
/* increment */
pcnt++ ;
if ( pcnt == 100 ) {
/* clear */
pcnt = 0 ;
/* update duty ratio */
dcntx = dcnt ;
}
}
}
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
/* disable A/D converter */
setup_adc_ports( NO_ANALOGS );
/* set directions */
set_tris_a( 0x00 ) ; /* all outputs */
set_tris_b( 0xff ) ; /* all inputs */
set_tris_c( 0x80 ) ;
/* initialize port values */
a_port = 0xff ; /* */
b_port = 0x00 ; /* */
c_port = 0xdf ; /* */
/* initialize pointer */
sindex = 0 ;
/* initialize counter */
pcnt = 0 ;
dcnt = 0 ;
dcntx = 0 ;
/* clear flags */
sflag = OFF ;
tflag = OFF ;
dflag = OFF ;
/* initialize timer 0 */
setup_counters( RTCC_INTERNAL , RTCC_DIV_8 );
set_timer0( 6 );
/* enable interrupt */
enable_interrupts( INT_RTCC );
enable_interrupts( INT_RDA );
enable_interrupts( GLOBAL );
}
UBYTE get_hex(UBYTE x)
{
UBYTE result ;
result = 0 ;
if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }
return result ;
}
回路図は、以下。
目次
前
次