搜索
bottom↓
回复: 4

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

[复制链接]

出0入0汤圆

发表于 2009-6-23 18:12:41 | 显示全部楼层 |阅读模式
最近在做无刷电机控制器,用了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入0汤圆

 楼主| 发表于 2009-6-23 21:52:33 | 显示全部楼层
怎么没人帮我看看呢,自己先顶一下。

出0入0汤圆

发表于 2009-6-25 07:23:49 | 显示全部楼层
什么叫调时基?你不是说频率不变吗?频率不变当然时基也就不会变了,

出0入0汤圆

 楼主| 发表于 2009-6-25 23:25:47 | 显示全部楼层
可以了,这款单片机非常好。不错,电流保护还缺点。

出0入0汤圆

发表于 2009-6-27 20:35:18 | 显示全部楼层
dsPIC很适合做电机控制,至于电流保护上面本身电机控制模块上就有一个错误输入引脚可以用来监视错误.不过还是外部搭建限流电路比较保险,最好能做一个电流环.
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 18:11

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表