|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区
您需要 登录 才可以下载或查看,没有账号?立即注册
×
#include "stc15.h"
#define CYCLE 0x1000L //定义PWM周期(最大值为32767)
typedef unsigned char BYTE;
typedef unsigned int WORD;
//-----------------------------------------------
#define FOSC 11059200L
#define T1MS (65536-FOSC/1000) //1T模式
//#define T1MS (65536-FOSC/12/1000) //12T模式
//sfr AUXR = 0x8e; //Auxiliary register
//sbit P10 = P1^0;
int i;
int j;
#include <math.h> //Keil library
#include <stdio.h> //Keil library
#include <INTRINS.H>
unsigned int DUTY1 = 3000; //定义占空比为50%
unsigned int DUTY2 = 3000; //定义占空比为50%
#define PWMC (*(unsigned int volatile xdata *)0xfff0)
#define PWMCH (*(unsigned char volatile xdata *)0xfff0)
#define PWMCL (*(unsigned char volatile xdata *)0xfff1)
#define PWMCKS (*(unsigned char volatile xdata *)0xfff2)
#define PWM2T1 (*(unsigned int volatile xdata *)0xff00)
#define PWM2T1H (*(unsigned char volatile xdata *)0xff00)
#define PWM2T1L (*(unsigned char volatile xdata *)0xff01)
#define PWM2T2 (*(unsigned int volatile xdata *)0xff02)
#define PWM2T2H (*(unsigned char volatile xdata *)0xff02)
#define PWM2T2L (*(unsigned char volatile xdata *)0xff03)
#define PWM2CR (*(unsigned char volatile xdata *)0xff04)
#define PWM3T1 (*(unsigned int volatile xdata *)0xff10)
#define PWM3T1H (*(unsigned char volatile xdata *)0xff10)
#define PWM3T1L (*(unsigned char volatile xdata *)0xff11)
#define PWM3T2 (*(unsigned int volatile xdata *)0xff12)
#define PWM3T2H (*(unsigned char volatile xdata *)0xff12)
#define PWM3T2L (*(unsigned char volatile xdata *)0xff13)
#define PWM3CR (*(unsigned char volatile xdata *)0xff14)
#define PWM4T1 (*(unsigned int volatile xdata *)0xff20)
#define PWM4T1H (*(unsigned char volatile xdata *)0xff20)
#define PWM4T1L (*(unsigned char volatile xdata *)0xff21)
#define PWM4T2 (*(unsigned int volatile xdata *)0xff22)
#define PWM4T2H (*(unsigned char volatile xdata *)0xff22)
#define PWM4T2L (*(unsigned char volatile xdata *)0xff23)
#define PWM4CR (*(unsigned char volatile xdata *)0xff24)
#define PWM5T1 (*(unsigned int volatile xdata *)0xff30)
#define PWM5T1H (*(unsigned char volatile xdata *)0xff30)
#define PWM5T1L (*(unsigned char volatile xdata *)0xff31)
#define PWM5T2 (*(unsigned int volatile xdata *)0xff32)
#define PWM5T2H (*(unsigned char volatile xdata *)0xff32)
#define PWM5T2L (*(unsigned char volatile xdata *)0xff33)
#define PWM5CR (*(unsigned char volatile xdata *)0xff34)
#define PWM6T1 (*(unsigned int volatile xdata *)0xff40)
#define PWM6T1H (*(unsigned char volatile xdata *)0xff40)
#define PWM6T1L (*(unsigned char volatile xdata *)0xff41)
#define PWM6T2 (*(unsigned int volatile xdata *)0xff42)
#define PWM6T2H (*(unsigned char volatile xdata *)0xff42)
#define PWM6T2L (*(unsigned char volatile xdata *)0xff43)
#define PWM6CR (*(unsigned char volatile xdata *)0xff44)
#define PWM7T1 (*(unsigned int volatile xdata *)0xff50)
#define PWM7T1H (*(unsigned char volatile xdata *)0xff50)
#define PWM7T1L (*(unsigned char volatile xdata *)0xff51)
#define PWM7T2 (*(unsigned int volatile xdata *)0xff52)
#define PWM7T2H (*(unsigned char volatile xdata *)0xff52)
#define PWM7T2L (*(unsigned char volatile xdata *)0xff53)
#define PWM7CR (*(unsigned char volatile xdata *)0xff54)
#define uchar unsigned char
#define uint unsigned int
#define DataPort P2 //LCD1602数据端口
sbit SCL=P1^0; //IIC时钟引脚定义
sbit SDA=P1^1; //IIC数据引脚定义
sbit LCM_RS=P4^0; //LCD1602命令端口
sbit LCM_RW=P4^1; //LCD1602命令端口
sbit LCM_EN=P4^2; //LCD1602命令端口
sbit P1_1=P0^3;
sbit P1_2=P0^4;
sbit beep=P1^3;
sbit light=P0^4;
sbit vvv=P4^3; //LCD1602命令端口
#define SlaveAddress 0xA6 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
//ALT ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A
//typedef unsigned char BYTE;
//typedef unsigned short WORD;
BYTE equal[6];
BYTE BUF[8]; //接收数据缓存区
uchar ge,shi,bai,qian,wan; //显示变量
int dis_data1; //变量
int dis_data2; //变量
int dis_data3; //变量
int count;
float Roll,Pitch,zz,Q,T,K;
int iin=0;
int iIncpid;
int SetPoint; //设定目标
typedef struct PID
{
int SetPoint; //设定目标
long SumError; //误差累计
double Proportion; //比例常数
double Integral; //积分常数
double Derivative; //微分常数
int LastError; //Error[-1]
int PrevError; //Error[-2]
} PID;
static PID sPID;
static PID *sptr = &sPID;
void delay(unsigned int k);
void InitLcd(); //初始化lcd1602
void Init_ADXL345(void); //初始化ADXL345
void WriteDataLCM(uchar dataW);
void WriteCommandLCM(uchar CMD,uchar Attribc);
void DisplayOneChar(uchar X,uchar Y,uchar DData);
void conversion(uint temp_data);
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data); //单个写入数据
uchar Single_Read_ADXL345(uchar REG_Address); //单个读取内部寄存器数据
void Multiple_Read_ADXL345(); //连续的读取内部寄存器数据
//------------------------------------
void Delay5us();
void Delay5ms();
void ADXL345_Start();
void ADXL345_Stop();
void ADXL345_SendACK(bit ack);
bit ADXL345_RecvACK();
void ADXL345_SendByte(BYTE dat);
BYTE ADXL345_RecvByte();
void ADXL345_ReadPage();
void ADXL345_WritePage();
//-----------------------------------
//-----------------倾角显示开始---------------------//
void conversion(uint temp_data)
{
wan=temp_data/10000+0x30 ;
temp_data=temp_data%10000; //取余运算
qian=temp_data/1000+0x30 ;
temp_data=temp_data%1000; //取余运算
bai=temp_data/100+0x30 ;
temp_data=temp_data%100; //取余运算
shi=temp_data/10+0x30 ;
temp_data=temp_data%10; //取余运算
ge=temp_data+0x30;
}
/*******************************/
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i<k;i++)
{
for(j=0;j<121;j++)
{;}}
}
/*******************************/
void WaitForEnable(void)
{
DataPort=0xff;
LCM_RS=0;LCM_RW=1 ;_nop_();
LCM_EN=1;_nop_();_nop_();
while(DataPort&0x80);
LCM_EN=0;
}
/*******************************/
void WriteCommandLCM(uchar CMD,uchar Attribc)
{
if(Attribc)WaitForEnable();
LCM_RS=0;LCM_RW=0;_nop_();
DataPort=CMD;_nop_();
LCM_EN=1;_nop_();_nop_();LCM_EN=0;
}
/*******************************/
void WriteDataLCM(uchar dataW)
{
WaitForEnable();
LCM_RS=1;LCM_RW=0;_nop_();
DataPort=dataW;_nop_();
LCM_EN=1;_nop_();_nop_();LCM_EN=0;
}
/***********************************/
void InitLcd()
{
WriteCommandLCM(0x38,1);
WriteCommandLCM(0x08,1);
WriteCommandLCM(0x01,1);
WriteCommandLCM(0x06,1);
WriteCommandLCM(0x0c,1);
}
/***********************************/
void DisplayOneChar(uchar X,uchar Y,uchar DData)
{
Y&=1;
X&=15;
if(Y)X|=0x40;
X|=0x80;
WriteCommandLCM(X,1);
WriteDataLCM(DData);
}
/**************************************
延时5微秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数,注意时钟过快时需要修改
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
/**************************************
延时5毫秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5ms()
{
WORD n = 560;
while (n--);
}
/**************************************
起始信号
**************************************/
void ADXL345_Start()
{
SDA = 1; //拉高数据线
SCL = 1; //拉高时钟线
Delay5us(); //延时
SDA = 0; //产生下降沿
Delay5us(); //延时
SCL = 0; //拉低时钟线
}
/**************************************
停止信号
**************************************/
void ADXL345_Stop()
{
SDA = 0; //拉低数据线
SCL = 1; //拉高时钟线
Delay5us(); //延时
SDA = 1; //产生上升沿
Delay5us(); //延时
}
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void ADXL345_SendACK(bit ack)
{
SDA = ack; //写应答信号
SCL = 1; //拉高时钟线
Delay5us(); //延时
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
/**************************************
接收应答信号
**************************************/
bit ADXL345_RecvACK()
{
SCL = 1; //拉高时钟线
Delay5us(); //延时
CY = SDA; //读应答信号
SCL = 0; //拉低时钟线
Delay5us(); //延时
return CY;
}
/**************************************
向IIC总线发送一个字节数据
**************************************/
void ADXL345_SendByte(BYTE dat)
{
BYTE i;
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1; //移出数据的最高位
SDA = CY; //送数据口
SCL = 1; //拉高时钟线
Delay5us(); //延时
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
ADXL345_RecvACK();
}
/**************************************
从IIC总线接收一个字节数据
**************************************/
BYTE ADXL345_RecvByte()
{
BYTE i;
BYTE dat = 0;
SDA = 1; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
SCL = 1; //拉高时钟线
Delay5us(); //延时
dat |= SDA; //读数据
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
return dat;
}
//******单字节写入*******************************************
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data)
{
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf22页
ADXL345_SendByte(REG_data); //内部寄存器数据,请参考中文pdf22页
ADXL345_Stop(); //发送停止信号
}
//********单字节读取*****************************************
uchar Single_Read_ADXL345(uchar REG_Address)
{ uchar REG_data;
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(REG_Address); //发送存储单元地址,从0开始
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress+1); //发送设备地址+读信号
REG_data=ADXL345_RecvByte(); //读出寄存器数据
ADXL345_SendACK(1);
ADXL345_Stop(); //停止信号
return REG_data;
}
//*********************************************************
//
//连续读出ADXL345内部加速度数据,地址范围0x32~0x37
//
//*********************************************************
void Multiple_read_ADXL345(void)
{ uchar i;
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(0x32); //发送存储单元地址,从0x32开始
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress+1); //发送设备地址+读信号
for (i=0; i<6; i++) //连续读取6个地址数据,存储中BUF
{
BUF = ADXL345_RecvByte(); //BUF[0]存储0x32地址中的数据
if (i == 5)
{
ADXL345_SendACK(1); //最后一个数据需要回NOACK
}
else
{
ADXL345_SendACK(0); //回应ACK
}
}
ADXL345_Stop(); //停止信号
Delay5ms();
}
//*****************************************************************
//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345()
{
Single_Write_ADXL345(0x31,0x0B); //测量范围,正负16g,13位模式
Single_Write_ADXL345(0x2C,0x08); //速率设定为12.5 参考pdf13页
Single_Write_ADXL345(0x2D,0x08); //选择电源模式 参考pdf24页
Single_Write_ADXL345(0x2E,0x80); //使能 DATA_READY 中断
Single_Write_ADXL345(0x1E,0x00); //X 偏移量 根据测试传感器的状态写入pdf29页
Single_Write_ADXL345(0x1F,0x00); //Y 偏移量 根据测试传感器的状态写入pdf29页
Single_Write_ADXL345(0x20,0x05); //Z 偏移量 根据测试传感器的状态写入pdf29页
}
//***********************************************************************
//显示x轴
void display_x()
{
int temp=(sptr->SetPoint - Pitch);
if(temp<0)
{
temp=-temp;
DisplayOneChar(2,0,'-'); //显示正负符号位
}
else DisplayOneChar(2,0,' '); //显示空格
conversion(temp); //转换出显示需要的数据
DisplayOneChar(0,0,'X'); //第0行,第0列 显示X
DisplayOneChar(1,0,':');
DisplayOneChar(3,0,qian);
DisplayOneChar(4,0,bai);
DisplayOneChar(5,0,shi);
DisplayOneChar(6,0,ge);
}
//***********************************************************************
//显示y轴
void display_y()
{
if(Pitch<0){
Pitch=-Pitch;
DisplayOneChar(2,1,'-'); //显示正负符号位
}
else DisplayOneChar(2,1,' '); //显示空格
conversion(Pitch); //转换出显示需要的数据
DisplayOneChar(0,1,'Y'); //第1行,第0列 显示y
DisplayOneChar(1,1,':');
DisplayOneChar(3,1,qian);
DisplayOneChar(4,1,bai);
DisplayOneChar(5,1,shi);
DisplayOneChar(6,1,ge);
}
//***********************************************************************
//显示z轴
void display_z()
{
if(iin<0){
iin=-iin;
DisplayOneChar(10,1,'-'); //显示负符号位
}
else DisplayOneChar(10,1,' '); //显示空格
conversion(iin); //转换出显示需要的数据
DisplayOneChar(9,1,'Z'); //第0行,第10列 显示Z
DisplayOneChar(11,1,':');
DisplayOneChar(12,1,qian);
DisplayOneChar(13,1,bai);
DisplayOneChar(14,1,shi);
DisplayOneChar(15,1,ge);
}
//----------------倾角显示结束---------------------//
sfr PIN_SW2 = 0xba;
/*====== Initialize PID Structure PID参数初始化 =====*/
void IncPIDInit(void)
{
sptr->SumError = 0;
sptr->LastError = 0; //Error[-1]
sptr->revError = 0; //Error[-2]
sptr->roportion = 15; //比例常数
sptr->Integral =0; //积分常数
sptr->Derivative = 0; //微分常数
//sptr->SetPoint = 90;
}
/*===== 增量式PID计算部分=========*/
int IncPIDCalc(int NextPoint)
{
register int iError, iIncpid; //当前误差
iError = sptr->SetPoint - NextPoint; //增量计算
iIncpid = sptr->roportion * iError //E[k]项
- sptr->Integral * sptr->LastError //E[k-1]项
+ sptr->Derivative * sptr->revError; //E[k-2]项 //存储误差,用于下次计算
sptr->revError = sptr->LastError;
sptr->LastError = iError; //返回增量值
if(iIncpid >= 1090)iIncpid=1090;
if(iIncpid <= -1080)iIncpid=-1080;
return(iIncpid);
}
void cqq()
{
Multiple_Read_ADXL345(); //连续读出数据,存储在BUF中
dis_data1=(BUF[1]<<8)+BUF[0]; //合成数据
dis_data2=(BUF[3]<<8)+BUF[2]; //合成数据
dis_data3=(BUF[5]<<8)+BUF[4]; //合成数据
Q=(float)dis_data1*3.9;
T=(float)dis_data2*3.9;
K=(float)dis_data3*3.9;
Roll=(float)(((atan2(K,Q)*180)/3.1416)-90); //X轴角度值
Pitch=(float)(((atan2(K,T)*180)/3.1416)); //Y轴角度值
zz=(float)((atan2(Q,K)*180)/3.1416);
}
//char filter()
//{
// long sum=0;
// for(count=0;count<10;count++)
// { cqq();
// sum+=Pitch;
// }
// return(char)(sum/10);
//}
void K1CHECK()
{
TR1=0;
sptr->SetPoint =110;
}
void K2CHECK()
{
TR1=1;
}
void tm1_isr() interrupt 3 using 1
{
i++;
if(i==1000)
sptr->SetPoint = 70;
if(i==2000)
sptr->SetPoint = 110;
if(i==3000)
{
sptr->SetPoint = 70;
i=0; j++;
}
}
void main()
{
vvv=1;
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
PIN_SW2 |= 0x80; //使能访问XSFR
PWMCFG = 0x00; //配置PWM的输出初始电平为低电平
PWMCKS = 0x00; //选择PWM的时钟为Fosc/(0+1)
PWMC = CYCLE; //设置PWM周期
PWM2T1 = 0x0000; //设置PWM2第1次反转的PWM计数
PWM2T2 = 2048;//CYCLE * DUTY1 / 100; //设置PWM2第2次反转的PWM计数
PWM3T1 = 0x0000; //设置PWM2第1次反转的PWM计数
PWM3T2 = 2048;//CYCLE * DUTY2 / 100; //设置PWM2第2次反转的PWM计数
PWM3CR = 0x08; //选择PWM2输出到P4.5,不使能PWM2中断
PWM2CR = 0x00; //选择PWM2输出到P3.7,不使能PWM2中断
PWMCR = 0x03; //使能PWM信号输出
PWMCR |= 0x40; //使能PWM归零中断
PWMCR |= 0x80; //使能PWM模块
PIN_SW2 &= ~0x80;
EA = 1;
delay(500);delay(500);delay(500);delay(500);delay(500);
delay(500);delay(500);delay(500);delay(500);delay(500);
delay(500); //上电延时
InitLcd(); //液晶初始化ADXL345
Init_ADXL345(); //初始化ADXL345
IncPIDInit();
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x9A; //设置定时初值
TH1 = 0xA9; //设置定时初值
TF1 = 0; //清除TF0标志
ET1 = 1; //使能定时器0中断
EA = 1;
while (1)
{
if(P1_1==0)
delay(500);
if(P1_1==0)
K1CHECK();
if(P1_2==0)
delay(500);
if(P1_2==0)
K2CHECK();
cqq();
// Pitch=filter();
display_x(); //---------显示X轴
display_y(); //---------显示Y轴
display_z(); //---------显示Z轴
if((sptr->SetPoint - Pitch)>3 ||(sptr->SetPoint - Pitch)<-3)
iin=IncPIDCalc(Pitch);
if(j==3)
{
sptr->SetPoint = 0;
TR1=0;
if(sptr->SetPoint -Pitch==0)
{
beep=0;
light=0;
}
}
} }
void pwm_isr() interrupt 22 using 1
{
if (PWMIF & 0x40)
{
PWMIF &= ~0x40;
DUTY1=3000+iin;
DUTY2=3000-iin;
PIN_SW2 |= 0x80;
PWM2T2 = DUTY1 ; //设置PWM2第2次反转的PWM计数
PWM3T2 = DUTY2 ; //设置PWM2第2次反转的PWM计数
PIN_SW2 &= ~0x80;
}
} |
|