下面這個程式是目前剛完成PWM基本測試的內容
使用的MCU大家應該不陌生-- C8051F300
大致上就是輪替送出PWM的功能
//-----------------------------------------------------------------------------
// ROBO_ARM.c
//-----------------------------------------------------------------------------
// AUTH: Nichal
// DATE: 2008/11/27
//
// Target: C8051F300
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include // SFR declarations
//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for 'F30x
//-----------------------------------------------------------------------------
sfr16 DP = 0x82; // data pointer
sfr16 TMR2RL = 0xca; // Timer2 reload value
sfr16 TMR2 = 0xcc; // Timer2 counter
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK 24500000 // SYSCLK frequency in Hz
#define BAUDRATE 9600 // Baud rate of UART in bps
#define SAMPLE_RATE 50 // Sample frequency in Hz
#define SERVO1_PWM SERVO1=1
#define SERVO2_PWM SERVO2=1
#define SERVO3_PWM SERVO3=1
#define SERVO4_PWM SERVO4=1
#define TMH (65536-(SYSCLK/12/SAMPLE_RATE))/256
#define TML (65536-(SYSCLK/12/SAMPLE_RATE))%256
#define MAX_ANGLE 62200
#define MIN_ANGLE 12400
#define MID_ANGLE 37300
sbit SERVO1 = P0^0;
sbit SERVO2 = P0^1;
sbit SERVO3 = P0^2;
sbit SERVO4 = P0^3;
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------
void SYSCLK_Init (void);
void PORT_Init (void);
void Timer0_Init (void);
void Timer0_ISR (void);
void Timer2_Init (void);
void Timer2_Switch (unsigned int counts);
void Timer2_ISR (void);
//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
bit start_flag;
bit change_flag;
unsigned char servo_counts;
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void)
{
// Disable Watchdog timer
PCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer enable)
SYSCLK_Init (); // initialize oscillator
PORT_Init (); // initialize crossbar and GPIO
Timer2_Init ();
Timer0_Init ();
start_flag=0;
change_flag=0;
servo_counts=0;
EA=1;
while (1)
{
if (start_flag)
{
start_flag=0;
SERVO1_PWM;
Timer2_Switch(MID_ANGLE);
while (change_flag==0);
change_flag=0;
SERVO2_PWM;
Timer2_Switch(MID_ANGLE);
while (change_flag==0);
change_flag=0;
SERVO3_PWM;
Timer2_Switch(MID_ANGLE);
while (change_flag==0);
change_flag=0;
SERVO4_PWM;
Timer2_Switch(MID_ANGLE);
while (change_flag==0);
change_flag=0;
// add new servo here
}
}
}
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// This routine initializes the system clock to use the internal 24.5MHz
// oscillator as its clock source. Also enables missing clock detector reset.
//
void SYSCLK_Init (void)
{
OSCICN |= 0x03; // configure internal oscillator for
// its maximum frequency}
RSTSRC = 0x04; // enable missing clock detector
}
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
void PORT_Init (void)
{
XBR0 = 0xff;
XBR1 = 0x00;
XBR2 = 0x40;
P0MDOUT = 0xff;
P0MDIN = 0xff;
P0 = 0;
}
//-----------------------------------------------------------------------------
// Timer0_Init
//-----------------------------------------------------------------------------
// 20mS Timer
//
void Timer0_Init (void)
{
TCON &= 0xcf; // Stop Timer0; Clear TF0
CKCON &= ~0x08; // Timer0 uses SYSCLK/12
TMOD |= 0x01; // Timer0 in 16-bit mode
TH0 = TMH; // 20mS interrupt
TL0 = TML;
ET0 = 1; // enable Timer0 interrupts
TR0 = 1; // Timer0 enabled
}
//-----------------------------------------------------------------------------
// Timer0_ISR
//-----------------------------------------------------------------------------
//
//
void Timer0_ISR (void) interrupt 1 // wheel signal off
{
TF0 = 0;
TH0 = TMH;
TL0 = TML;
start_flag=1;
servo_counts=0;
}
//-----------------------------------------------------------------------------
// Timer2_Init
//-----------------------------------------------------------------------------
// PWM Timer
//
void Timer2_Init (void)
{
TMR2CN = 0x00;
CKCON |= 0x20;
ET2 = 0;
TR2 = 0;
}
void Timer2_Switch (unsigned int counts)
{
TMR2 = -counts; // set to reload immediately
ET2 = 1; // disable Timer2 interrupts
TR2 = 1;
}
//-----------------------------------------------------------------------------
// Timer2_ISR
//-----------------------------------------------------------------------------
//
void Timer2_ISR (void) interrupt 5
{
TF2H = 0; // clear Timer2 interrupt flag
TR2 = 0;
P0 = 0;
change_flag=1;
}
看完一大片程式碼
有沒有眼花撩亂
沒關係
改看看輸出的波形測試
程式中的Timer0是用來產生歸零動作的
也就是所謂的20mS信號
不過因為內部振盪器的誤差
所以實際值只有19.7mS
這個值是可以調整的
只是因為我的需求到這樣就夠了
所以就沒有再修過
看看這一張
非常準確的1.5mS
代表信號是真的可以修得非常準的
只是需不需要修到這麼準罷了!!
這個信號是用MID_ANGLE的參數所產生的波形
而這一張0.5mS(500uS)
則是用MIN_ANGLE所產生的波形
再來看一張2.5mS
是用MAX_ANGLE所產生的波形
為了看看輪替輸出的樣子
把所有的測棒通通都接上控制板
這就是最後輸出的樣子
因為只有四根測棒
所以先開4CH的PWM給大家看看就好
其實這一類的程式
很多網頁或書籍都有說明跟範例
不過絕大多數會用同一個埠來輪替輸出
以運算的方式強制從該埠的第0腳到第7腳輸出
然而對於腳位較少
而且腳位分布不固定的MCU
(例如一個埠只有0,3,4,6,7這幾隻腳)
這樣的寫法會比較有彈性
只要每增加一個 SERVO
在程式的最前方宣告一下
#define SERVOX_PWM SERVO1=1
sbit SERVOX=腳位;
然後再到主程式裡
標記
// add new servo here的地方
再加上一段程式碼
************************************
SERVOX_PWM;
Timer2_Switch(MID_ANGLE);
while (change_flag==0);
change_flag=0;
************************************
這樣就可以再新增一組控制項(多一組PWM出來)
其中MID_ANGLE的參數是可以修正的
對應到的是實際需求的角度信號
有了這個基本功能後
接下來就要加入通訊功能
這樣才有辦法透過PC來控制多變的機械手臂動作
敬請期待~~~
ps.
最近工作比較忙
沒辦法天天更新
請大家多多包涵