[求助]PIC30f2010+IR2011+HC595+1602无刷控制器,PIC的PDC1、2、3寄存器怎么变成调时基了

2020-02-10 08:40发布

最近在做无刷电机控制器,用了PIC30f2010,也参考了官方的例子。开机运行时要慢慢启转动的,我是控制PDC的值,先为0再一直加到512。这个功能是行的,但是在过流时要把占空比调小,就是转速要慢,让它电流值在那个范围内,我是这样做的,一当有电流超过设定值就减一个PDC的值,电流如果没有到设定值就加一个PDC值,可到那运行时却变成调时基了,PDC的值为512时是没有时基的,511就有一点点时基了,时基频率是设定值,但脉冲很窄。这个值越小时基就越多,PDC明明是调占空比的怎么会变成调时基(PWM)去了呢?程序如下:写的有点乱,也比较笨,别见笑!

//----------------------------------------------------------------------
//**************** 振荡器 ************************************
//#define dFoscExt 5 000 000 // 外部晶振或时钟频率(Hz)
//#define dPLL 8 // PLL 比率
//#define dLoopTimeInSec 0.00005 // PWM 周期 - 100 uS, 10Khz PWM
//#define dDeadTimeSec 0.000 002 // 以秒为单位的死区时间
// Derived
//#define dFosc (5 000 000*8) // 时钟频率(Hz)
//#define dFcy (40 000 000/4) // 指令频率(Hz)
//#define dTcy (1.0/10 000 000) // 指令周期(s)=0.000 000 1s=100ns
//#define dDeadTime (int)(0.000 002*10 000 000) // 以dTcys 为单位的死区时间=0.000 000 000 0002
//#define dLoopInTcy (dLoopTimeInSec/dTcy) // 以Tcy 为单位的基本循环周期
//#define dDispLoopTime 0.100 // 显示和按钮状态查询循环

#include "p30F2010.h"
  _FOSC(0x0c306);                 //XT振荡,4倍频晶振.
  _FWDT(WDT_OFF);                 //关闭看门狗定时器
  _FBORPOR(PBOR_OFF & MCLR_EN);   //掉电复位禁止,MCLR复位使能。
  _FGS(CODE_PROT_OFF);            //代码保护禁止
#define FCY 10000000// xtal = 5.0Mhz ; PLLx8
#define MILLISEC FCY/10000// 1 mS 延迟常数
#define FPWM 39000
#define S2 LATCbits.LATC14
#define EN2 LATCbits.LATC13
#define RS2 LATDbits.LATD0        //15
#define HC595_SCLK LATDbits.LATD1        //14
#define HC595_SID LATFbits.LATF2        //18
#define HC595_enable LATFbits.LATF3        //17

void InitTMR3(void);
void InitADC10(void);
void AverageADC(void);
void DelayNmSec(unsigned int N);
void InitMCPWM(void);
void CalculateDC(void);
void GetSpeed(void);
struct {
unsigned RunMotor : 1;
unsigned Minus : 1;
unsigned xsbit : 1;                //0.5S显示一次
unsigned Ysbit : 1;                //电机刚起的时候的延时
unsigned tdybit : 1;        //太低压了保护
unsigned dzbit : 1;                //堵转的位
unsigned dlbit : 1;                //短路的位
unsigned zfbit : 1;                //正反转的位
unsigned addybit : 1;                //ad低压
unsigned adglbit : 1;                //ad过流
unsigned unused : 6;
} Flags;
unsigned int HallValue;
unsigned int Ys;                //刚开电机时电压和电流不检测延时一下
unsigned int ysmoto,glms;        //慢起动
unsigned int glys;
unsigned int gl[10];
unsigned int dy[10];
unsigned int dybit;
unsigned int glbit;
unsigned int i,j,k,l,m;
unsigned long glnum,dynum;
unsigned long vmoto,zsmoto,zsbit,zsjs;
unsigned char  ZF[ ]={'U',':','.','V',' ','B','A','T','%','R','P','M'};
unsigned int test;
unsigned int dzbf,dzbfjs;        //堵转保护
unsigned int ADAD,state;
/************************************************************/
void delay(unsigned int i)
{
while(i--);
}
/*************************************************************
以下是低端驱动器表。在此StateLoTable 中,
在低端驱动器施加PWM 信号,而高端驱动器为“导通”或“截止”状态。
在本练习中使用此表。
*************************************************************/
unsigned int StateLoTable[] = {0x0000, 0x02001, 0x0810, 0x0801,0x0204, 0x2004, 0x0210, 0x0000};
/****************************************************************
以下是变化通知引脚CN5、CN6 和CN7 的中断向量。
当霍尔传感器改变状态时,将引起中断,指令执行将转到下面的子程序。
然后用户必须读端口B 的第3 位、第4 位和第5 位,
对读到的值进行移位和调节以使之读作1、2……6。
然后将调整后的值用作查找表StateLoTable 中的偏移量
以确定装入OVDCON 寄存器的值。
*****************************************************************/
void _ISR _CNInterrupt(void)
{
IFS0bits.CNIF = 0; // 清零标志
HallValue = PORTB & 0x0038; // 屏蔽其它位,保留RB3、RB4 和RB5
HallValue = HallValue >> 3; // 执行3 次右移
OVDCON = StateLoTable[HallValue];
zsbit++;
dzbf=0;
//if(HallValue==1)
//S2=!S2;
}
/*********************************************************************
ADC 中断用给定的电位计值装载PDCx 寄存器。
仅在电机运行时执行此操作。
*********************************************************************/
void _ISR _ADCInterrupt(void)
{
IFS0bits.ADIF = 0;
if (Flags.RunMotor)
{
//ADAD=ADCBUF0>>1;
//ADAD=ADAD-ysmoto-glms;
//PDC1 = ADAD; // 赋值……>>等于/2笨蛋
//PDC2 = PDC1; // 并装载所有的三个PWM……
//PDC3 = PDC1; // 占空比寄存器

        if(Flags.addybit==0){
        dy[dybit]=ADCBUF1;
        if(dybit++>=8)
        {
                dybit=0;Flags.addybit=1;
        }
        }

        if(Flags.adglbit==0){
        gl[glbit]=ADCBUF2;
        if(glbit++>=8)
        {
        glbit=0;Flags.adglbit=1;       
        }
        }
}
}
/*********************************************************************
外中断,下降沿触发,短路保护
*********************************************************************/
void _ISR _INT0Interrupt(void)
{
IFS0bits.INT0IF = 0;
//PWMCON1 = 0x0700; // 禁止PWM 输出
//OVDCON = 0x0000; // 将PWM 改写为低电平
Flags.RunMotor = 0; // 复位运行标志
Flags.dlbit=1;
}
/*******************************************************************************************************************/
//发送一个字节(底层函数)
void lcm_w_byte(unsigned char bbyte) {
        unsigned char i;
        for(i=0;i<8;i++){
                   HC595_SID=bbyte&0x01;                                 //取出最高位
                DelayNmSec(1);
                HC595_SCLK=0;
                DelayNmSec(1);
                   HC595_SCLK=1;
                   bbyte>>=1;                                                 //左移
                HC595_enable=0;
                DelayNmSec(1);
                HC595_enable=1;
                DelayNmSec(1);
           }  
}
/*************************************/
void enable2(void)
{
                EN2=1;                                 //E=1;
                DelayNmSec(1);                                                //当系统时钟为1MHz时,延时ns
                EN2=0;                                //E=0;
}
/****************************指令*****************************/
void writecmd2(unsigned char command)
{
        unsigned char command_temp;        
   
    command_temp = command;
               
           RS2=0;      //命令;
        DelayNmSec(1);
           lcm_w_byte(command_temp);
           enable2();
        DelayNmSec(1);
        RS2=1;
}
/*******************************数据*******************************/
void writedata2(unsigned char Adata)
{
        unsigned char data_temp;
               
        data_temp = Adata;       
           EN2=0;
        DelayNmSec(1);
           RS2=1;
        DelayNmSec(12);
           lcm_w_byte(data_temp);
           DelayNmSec(1);
           enable2();
}

/*****************************位址*****************************/
void setcoordinate2(unsigned char x,unsigned char y)
{
    unsigned char address;
    if (y == 0) address = 0x80 + x;
    else
       address = 0xc0 + x;
    writecmd2(address);
}
/**************************送字符**************************/
void writestring2(unsigned char X,unsigned char Y,unsigned char s)
{
           setcoordinate2(X, Y);
    writedata2(s);
}
/******************************************************/
void initLCD2(void)
{       
        writecmd2(0x38);                              //4bit   只要改成38就为8位
        DelayNmSec(2);
        enable2();
        DelayNmSec(2);
        writecmd2(0x38);                              //4bit
        DelayNmSec(2);
        writecmd2(0x0c);                              //显示开
        DelayNmSec(2);
        writecmd2(0x01);                              //显示清屏
        DelayNmSec(2);
    writecmd2(0x06);                              //显示光标移动设置                              
           DelayNmSec(2);
}
/************************************************************************
**Tmr1初始化函数
*************************************************************************/
void InitTMR1(void)
{
T1CON=0x0010;   // internal Tcy/256 clock
TMR1=0xcf2c;
PR1=0xffff;          //16   16*62=1ms
IFS0bits.T1IF=0;  //清除TMR1的中断标志
IEC0bits.T1IE=1;  //使能中断

}
/*******************计算电压和电流***********************/
void js(void)
{
                unsigned char i;
if (Flags.RunMotor)
{
if(Flags.addybit){
                for(i=0;i<8;i++)
                dynum+=dy;
                dynum=dynum>>3;
                vmoto=dynum;
                if(dynum<372)                //低压
                {
                Flags.RunMotor = 0; // 复位运行标志
                Flags.tdybit=1;
                }                        //如果电压小于20V的话继电器关
                dynum=0;
                Flags.addybit=0;
}                               

if(Flags.adglbit){
                for(i=0;i<8;i++)
                glnum+=gl;
                glnum=glnum>>3;
                if(glnum>=512)                //抗干拢一下明天再试--10=4ms
                {
                glms--;
                if(glms<20) glms=20;        //电流到这时转速就慢下来,
                }
                else
                {
                glms++;
                if(glms>510) glms=510;
                }
                glnum=0;
test = glms;
PDC1 = glms; // 赋值------------------------这就是处理电流后去给PDC寄存器的值,可是却变成调时基了(39K的载波)
PDC2 = glms; // 并装载所有的三个PWM……
PDC3 = glms;
Flags.adglbit=0;
}
}
}
/********************************************************
**定时器1中断服务
*********************************************************/
//void __attribute__((__interrupt__)) _T1Interrupt(void)
void _ISR _T1Interrupt(void)
{
TMR1=0xcf2c;      
IFS0bits.T1IF = 0; //清定时器中断标志
    if (Flags.RunMotor)        //10ms
    {
        zsjs++;
        if(zsjs>=50)
                {
                S2=!S2;js();
                Flags.xsbit=1;
                zsjs=0;
                zsmoto=zsbit*60/24*2;
                zsbit=0;
                }

        dzbf++;
        if(dzbf>=200)                                //如果超过两秒就认为堵转
        {
        dzbf=0;
        Flags.dzbit=1;
        Flags.RunMotor=0;
        }
    }   
}
/*******************************************************************************************************************/
int main(void)
{
TRISC = 0x9FFF;
TRISD = 0x0000;
TRISF = 0x0000;
LATD = 0xFFFF;
LATF = 0xFFFF;
LATE = 0x0000;
TRISE = 0xFFC0; // 设置为输出PWM 信号
CNEN1 = 0x00E0; // 使能CN5、CN6 和CN7
CNPU1 = 0x00E0; // 使能内部上拉
InitMCPWM();
InitADC10();
initLCD2();
InitTMR1();
INTCON2bits.INT0EP = 1;
IFS0bits.INT0IF = 0;
IEC0bits.INT0IE = 1;
IFS0bits.CNIF = 0; // 清零CNIF
IEC0bits.CNIE = 1; // 允许CN 中断
glms=511;
//Flags.Ysbit = 0;
//Flags.gjbit = 1;
//DelayNmSec(1000);
S2=1;                                //打开继电器
DelayNmSec(1000);        //3s
//DelayNmSec(100);        //100ms
// 在PORTB 上读霍尔位置传感器
HallValue = PORTB & 0x0038; // 屏蔽其它位,保留RB3、RB4 和RB5
HallValue = HallValue >> 3; // 右移以获得值1、2……6
OVDCON = StateLoTable[HallValue]; // 装载改写控制寄存器
PWMCON1 = 0x0777; // 使能PWM 输出
T1CONbits.TON = 1;
for(ysmoto=0;ysmoto<510;ysmoto++)
{
DelayNmSec(2);
PDC1 = ysmoto; // 赋值------------------开机慢慢启动,这是行的,可以改变速度。
PDC2 = PDC1; // 并装载所有的三个PWM……
PDC3 = PDC1;
}
ysmoto=0x0000;
Flags.RunMotor = 1; // 将标志置1

/*****************/
while(1)
{
DelayNmSec(100);
while (Flags.RunMotor) // 当电机运行时
{
        //if(Flags.xsbit){
        //Flags.xsbit=0;
        test=vmoto;
        //vmoto=vmoto*550/1024;
        writestring2(0,0,ZF[0]);
        writestring2(1,0,ZF[1]);
        writedata2((vmoto*550/1024/100)%10+48);
        writedata2((vmoto*550/1024/10)%10+48);
        writestring2(4,0,ZF[2]);
        writedata2((vmoto*550/1024%10)+48);
        writestring2(6,0,ZF[3]);
        writestring2(7,0,ZF[4]);
        writestring2(8,0,ZF[5]);
        writestring2(9,0,ZF[6]);
        writestring2(10,0,ZF[7]);
        writestring2(11,0,ZF[7]);
        writestring2(12,0,ZF[1]);
        writedata2(((vmoto*550/1024*10)/360)%10+48);
        writedata2(((vmoto*550/1024*10)/36)%10+48);
        writestring2(15,0,ZF[8]);
    writestring2(0,1,ZF[9]);
    writestring2(1,1,ZF[10]);
    writestring2(2,1,ZF[11]);
    writestring2(3,1,ZF[1]);
        writedata2((zsmoto/1000)%10+48);
        writedata2((zsmoto/100)%10+48);
        writedata2((zsmoto/10)%10+48);
        writedata2(zsmoto%10+48);
//DelayNmSec(200);
        //writestring2(8,1,ZF[4]);//AD
        //writedata2((test/1000)%10+48);
        writedata2((test/100)%10+48);
        writedata2((test/10)%10+48);
        writedata2(test%10+48);
        //writedata2((zsbit/1000)%10+48);
        //writedata2((zsbit/100)%10+48);
        //writedata2((zsbit/10)%10+48);
        //writedata2(zsbit%10+48);*/
        //}
}
        if((Flags.dlbit==1)||(Flags.dzbit==1))//如果短路堵转
        {
        PWMCON1 = 0x0700; // 禁止PWM 输出
        OVDCON = 0x0000; // 将PWM 改写为低电平
        DelayNmSec(1);
                //while(l<30)
                //{
                        while(k<1200)//k为展开速度
                        {
                                for(j=0;j<25;j++)
                                {
                                  if(j<=i)
                                  LATE=0xffea;
                                else
                                LATE=0xffc0;
                                }k++;
                        }i++;k=0;
                //if(i>=20) {i=20;l++;}
                //}
                //这里要显示什么故障
                state=0;
                while(1){                //死循环
                if(Flags.dlbit) state=1;
                if(Flags.dzbit) state=2;
                //if(Flags.dlbit) state=3;
                //if(Flags.dlbit) state=4;
                writestring2(13,1,state%10+48);
                }
        }
}
}
/*******************************************************************
以下代码用于设置ADC 寄存器,该代码可实现下列功能:
1. 1 个通道转换( 本例中,该通道为RB2/AN2)
2. PWM 触发信号启动转换
3. 电位计连接到CH0 和RB2
4. 手动停止采样和启动转换
5. 手动检查转换完成
*********************************************************************/
void InitADC10(void)
{
ADPCFG = 0xFFF8; // 将端口B 的RB0 到RB2 配置为模拟引脚;将其它引脚配置为数字引脚
ADCON1 = 0x0064; // PWM 启动转换
ADCON2 = 0x0208; // 同时采样4 个通道
ADCHS = 0x0002; // 将RB2/AN2 作为CH0 连接到电位计……
// ch1 连接母线电压、Ch2 连接电机, Ch3 连接电位计
ADCON3 = 0x0080; // Tad 来源于内部RC (4uS)
IFS0bits.ADIF = 0;
IEC0bits.ADIE = 1;
ADCON1bits.ADON = 1; // 启动ADC
}
/********************************************************************
InitMCPWM,对PWM 做以下初始化:
1. FPWM = 39000 hz
2. 独立的PWM
3. 使用OVDCON 控制输出
4. 用从电位计读取的ADC 值设置占空比
5. 将ADC 设置为由PWM 特殊触发信号触发
*********************************************************************/
void InitMCPWM(void)
{
PTPER = FCY/FPWM - 1;
PWMCON1 = 0x0700; // 禁止PWM
OVDCON = 0x0000; // 允许使用OVD 控制
PDC1 = 100; // 将PWM1、PWM2 和PWM3 初始化为100
PDC2 = 100;
PDC3 = 100;
//SEVTCMP = PTPER;
PWMCON2 = 0x0F00; // 后分频比设为1:16
PTCON = 0x8000; // 启动PWM
}
//---------------------------------------------------------------------
// 这是普通的1 ms 延迟程序,用于提供1 mS 到65.5 秒的延迟。
// 如果N = 1,则延迟为1 mS ;如果N = 65535,则延迟为65,535 mS。
// 注意FCY 用于计算。
// 请根据上述定义语句做出必要的更改(PLLx4 或PLLx8 等)
// 以计算出正确的FCY。
void DelayNmSec(unsigned int N)
{
unsigned int j;
while(N--)
        for(j=0;j < MILLISEC;j++);
}
0条回答

一周热门 更多>