yeah you can. you can use a timer and any port pin. the timer set the pin high for some duration of time, and reset it low for the rest of the time in one cycle. repeat it again infinitely. the required duty cycle is adjusted by setting the duration the pin set high compared to the duration it is pulled low. the switching frequency is determined by the length of one cycle.
so for example, if you want to drive a dc motor with switching frequency of 200 hz, then the length of one cycle is 1/200 = 5 ms, here is the code (i'm using sdcc):
#include <at89x2051.h>
void delay(unsigned char t) /* t in .1 ms */
void main(void){
unsigned char dutycycle;
/*
some code
*/
while(1){
dutycycle = P1;
/*
assuming dutycycle is determined by values inputted by user through P1
with precaution so as not to exceed 50
*/
P3_0 = 1;
delay(dutycycle);
P3_0 = 0;
delay(50 - dutycycle);
}
/*
other code
*/
this way, if you want a dutycycle of 50%, then P3_0 should be on for 2.5 ms (call delay with argument 25) and off for the next 2.5 ms. 20% means P3_0 on for 1 ms (call delay(10)
and off for 4 ms (call delay(40)
.
there are certainly other better ways to implement pwm on 89x2051 uC, it's just one popped out of my head, so please cmiiw.