有没有会九齐的大•神指导下

写的是pwm输出,但是需要经常改变波形。
用仿真器在我使用的电脑上边出来波形是正常的和我算的差不多有一点偏差但是问题不大
烧上芯片在芯片上读pwm输出就变得不准很奇怪。
我使用的是8M/2T/16分频 就像定一个周期600高电平480的,他在芯片真正跑的时候出来时变成周期600或者650 高电平450/500,我就很疑惑不知道是哪里出了问题

  • 这篇博客: 简单易上手 51蓝牙 PWM调速 避障 循迹小车(最强小车)中的 三、软件 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 完整代码可在本文末尾下载

    main.c

    #include <REGX52.H>
    #include "UART.h"
    #include "Timer0.h"
    #include "Nixie.h"
    #include "Delay.h"
    
    sbit IN1 = P1^0; // 左上
    sbit IN2 = P1^1; // 左下
    sbit IN3 = P1^2; // 右上
    sbit IN4 = P1^3; // 右上
    sbit ENA = P2^6; //使能A
    sbit ENB = P2^7; //使能B
    
    sbit out0 = P2^0; // 右边避障,有障碍物就亮,输出0
    sbit out1 = P2^1; // 左边避障,有障碍物就亮,输出0
    
    sbit outleft = P1^6; //左边循迹,亮灯返回值为1
    sbit outright = P1^7; //右边循迹,检测到黑线灭灯,返回0
    
    unsigned char PWM; //PWM波
    unsigned char date;//输入缓冲区
    static unsigned char speed = 100; //设置速度初始值
    
    void stop() // 停
    {
    	IN1=0;
    	IN2=0;
    	IN3=0;
    	IN4=0;
    }
    
    void forward() // 向前
    {
    	IN1=1;
    	IN2=0;
    	IN3=1;
    	IN4=0;	  
    }
    
    void back() // 向后
    {
    	IN1=0;
    	IN2=1;
    	IN3=0;
    	IN4=1;	
    }
    
    void left() // 向左,只有左轮动
    {
    	IN1=1;
    	IN2=0;
    	IN3=1;
    	IN4=1;
    }
    
    void avoid_left()//向左,左右伦同时转动
    {
    	IN1=1;
    	IN2=0;
    	IN3=0;
    	IN4=1;
    }
    
    void right() // 向右,只有右轮动
    {
    	IN1=1;
    	IN2=1;
    	IN3=1;
    	IN4=0;
    }
    
    void avoid_right()//向左,左右伦同时转动
    {
    	IN1=0;
    	IN2=1;
    	IN3=1;
    	IN4=0;
    }
    
    void increase(void)//加速
    {
    	speed += 5; // 每次增加5
    	if(speed >= 100) // 上限是100
    	{
    		speed = 100;
    	}
    }
    	
    void reduce(void)//减速
    {
    	speed -= 5; // 每次减少5
    	if(speed <= 0) // 下限是0
    	{
    		speed = 0;
    	}
    }
    
    void avoid(void)//避障模式
    {
    	if(out0 == 0) // 右边有障碍物,左转
    	{
    		avoid_left();
    	}
    	if(out1 == 0) // 左边有障碍物,右转
    	{
    		avoid_right();
    	}
    	if(out0 == 1 && out1 == 1) // 没有障碍物,前进
    	{
    		 forward();
    	}
    	if(out0 == 0 && out1 == 0) // 有障碍物,停止
    	{
    		 stop();
    	}
    }
    
    void Follow_the_trail (void)
    {
    	if(outleft == 0 && outright == 0)//悬空,停止移动
    	{
    		stop();
    	}
    	if(outleft == 1 && outright == 1) //在赛道上,直线行驶
    	{
    		forward();
    	}
    	if(outleft == 1 && outright == 0) //偏离赛道向右,因向左行驶
    	{
    		left();
    	}
    	if(outleft == 0 && outright == 1) //偏离赛道向左,因向右行驶
    	{
    		right();
    	}
    }
    
    //串口中断
    void Time_Int () interrupt 4
    {
    	if(RI == 1) // RI为1时软件置0
    	{
    		RI = 0; // 清除接受标志
    		date = SBUF; // 接收数据缓存在date中
    		switch (date)
    		{
    			case ('1'):
    			{
    				forward();
    				break;
    			}
    			case ('2'):
    			{
    				back();
    				break;
    			}
    			case ('3'):
    			{
    				left();
    				break;
    			}
    			case ('4'):
    			{
    				right();
    				break;
    			}
    			case ('0'):
    			{
    				stop();
    				break;
    			}
    			case ('5'):
    			{
    				increase();
    				break;
    			}
    			case ('6'):
    			{
    				reduce();
    				break;
    			}
    		}
    	}
    }
    
    //定时器0
    void time_control() interrupt 1
    	{
    		TL0 = 0x66;		//设置定时初值
    		TH0 = 0xFC;		//设置定时初值
    		PWM++;
    		if (PWM == 100)
    		{
    			PWM = 0;
    		}
    		if(PWM <= speed)//大于PWM波则打开使能
    		{
    			ENA = 1;
    			ENB = 1;
    		}
    		if(PWM > speed)//小于PWM波则关闭使能
    		{
    			ENA = 0;
    			ENB = 0;
    		}
    	}
    
    void main ()
    {
    	UsartConfiguration(); // 串口初始化
    	Timer0Init();//定时器0初始化
    	while(1)
    	{
    		//在数码管可以看到当前的速度是多少
    		Nixie(1, speed/100);
    		Delay(5);
    		Nixie(2, (speed/10)%10);
    		Delay(5);
    		Nixie(3, speed%10);
    		Delay(5);
    		//启动避障模式,将此模式存放在主函数当中
    		if(date == '7')
    		{
    			avoid();
    		}
    		//启动循迹模式,将此模式存放在主函数当中
    		if(date == '8')
    		{
    			Follow_the_trail();
    		}
    	}
    }

    UART.h(中断)

    #ifndef __UART_H__
    #define __UART_H__
    
    void UsartConfiguration(void);
    void UART_SendByte(unsigned char byte);
    
    #endif

    UART.c

    #include <REGX52.H>
    
    /**
       * @brief  串口初始化,9600bps@11.0592MHz
       * @param  无
       * @retval 无
       */
    
    void UsartConfiguration(void)		//9600bps@11.0592MHz
    {
    	PCON &= 0x7F;		//波特率不倍速
    	SCON = 0x50;		//8位数据,可变波特率
    	TMOD &= 0x0F;		//清除定时器1模式位
    	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
    	TL1 = 0xFD;		//设定定时初值
    	TH1 = 0xFD;		//设定定时器重装值
    	ET1 = 0;		//禁止定时器1中断
    	TR1 = 1;		//启动定时器1
    	ES = 1;        //开启串口中断
        EA = 1; 		//开启总中断
    }
    
    /**
       * @brief  串口发送一个字节数据
       * @param  byte 是接收的数据
       * @retval 无
       */
    
    void UART_SendByte(unsigned char byte)
    {
    	SBUF = byte;
    	while (TI == 0);
    	TI = 0;
    }

    Timer0.h(定时器0)

    #ifndef __TIMER0_H__
    #define __TIMER0_H__
    
    void Timer0Init(void);
    
    #endif

    Timer0.c

    #include <REGX52.H>
    
    /**
       * @brief  定时器0,1毫秒@11.0592MHz
       * @param  无
       * @retval 无
       */
    
    void Timer0Init(void)		//1毫秒@11.0592MHz
    {
    	TMOD &= 0xF0;		//设置定时器模式
    	TMOD |= 0x01;		//设置定时器模式
    	TL0 = 0x66;		//设置定时初值
    	TH0 = 0xFC;		//设置定时初值
    	TF0 = 0;		//清除TF0标志
    	TR0 = 1;		//定时器0开始计时
    	ET0 = 1;		//定时器开关
    	EA = 1;			//总开关
    }
    
    
    
    /*模板
    	void time_control() interrupt 1
    	{
    		static unsigned int counst;//局部变量,静态变量,防止每次进入中断,都将counst置为0
    		TL0 = 0x66;		//设置定时初值
    		TH0 = 0xFC;		//设置定时初值
    		counst++;
    		if (counst == 1000)
    		{
    			counst = 0;
    			
    		}
    	
    	}
    */

    Nixie.h(数码管)

    #ifndef __NIXIE_H__
    #define __NIXIE_H__
    
    void Nixie(unsigned char Location,Number);
    
    #endif
    

    Nixie.c

    #include <REGX52.H>
    #include "Delay.h"
    
    //数码管段码表
    unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    
    /**
      * @brief  数码管显示
      * @param  Location 要显示的位置,范围:1~8
      * @param  Number 要显示的数字,范围:段码表索引范围
      * @retval 无
      */
    void Nixie(unsigned char Location,Number)
    {
    	switch(Location)		//位码输出
    	{
    		case 1:P2_4=1;P2_3=1;P2_2=1;break;
    		case 2:P2_4=1;P2_3=1;P2_2=0;break;
    		case 3:P2_4=1;P2_3=0;P2_2=1;break;
    		case 4:P2_4=1;P2_3=0;P2_2=0;break;
    		case 5:P2_4=0;P2_3=1;P2_2=1;break;
    		case 6:P2_4=0;P2_3=1;P2_2=0;break;
    		case 7:P2_4=0;P2_3=0;P2_2=1;break;
    		case 8:P2_4=0;P2_3=0;P2_2=0;break;
    	}
    	P0=NixieTable[Number];	//段码输出
    	Delay(1);				//显示一段时间
    	P0=0x00;				//段码清0,消影
    }
    

    Delay.h(延时)

    #ifndef __DELAY_H__
    #define __DELAY_H__
    
    void Delay(unsigned int xms);
    
    #endif
    

    Delay.c

    
    /**
      * @brief  毫秒延时
      * @param  xms输入的毫秒
      * @retval 无
      */
    void Delay(unsigned int xms)	//@11.0592MHz
    {
    	unsigned char i, j;
    	while(xms--)
    	{
    		i = 2;
    		j = 199;
    		do
    		{
    			while (--j);
    		} while (--i);
    	}
    }