- 打卡等级:常住居民III
- 打卡总天数:142
- 最近打卡:2025-04-27 09:42:20
版主
- 积分
- 1780
|
发表于 2023-10-23 09:57:32
|
显示全部楼层
本帖最后由 STC32位8051芯片 于 2023-11-29 13:42 编辑
源代码如下:
#include "STC32G.h" //包含此头文件后,不需要再包含"reg51.h"头文件
#include "usb.h" //USB调试及复位所需头文件
/****************************** 用户定义宏 ***********************************/
#define MAIN_Fosc 35000000L //定义主时钟
#define Timer0_Reload (65536UL -(MAIN_Fosc / 100)) //Timer 0 中断频率, 50次/秒
/*****************************************************************************/
#define PWM5_1 0x00 //P2.0
#define PWM6_1 0x00 //P2.1
#define ENO5P 0x01
#define ENO6P 0x04
#define PWM_PERIOD 20000 //设置周期值
/***************************** 本地变量声明 **********************************/
struct pointI{
int x;
int y;
};
struct pointF{
float x;
float y;
};
struct pointI rad2pwm(struct pointF rad);
struct pointF cor2rad(struct pointF cor);
void move(float x,float y);
void walk_panel(void);
void walk_home(void);
void walk_A4_ai(void);
struct pointF cvt_point(struct pointI src);
void corr(void);
float M[9]={0};//透视变换矩阵
u16 PWM5_Duty;
u16 PWM6_Duty;
bit PWM5_Flag;
bit PWM6_Flag;
void UpdatePwm(u16 pwm5,u16 pwm6);
#define Baudrate1 (65536 - MAIN_Fosc / 115200 / 4)
#define UART1_BUF_LENGTH 128
u8 TX1_Cnt;
u8 RX1_Cnt;
bit B_TX1_Busy;
u8 RX1_Buffer[UART1_BUF_LENGTH];
/************* UART函数 **************/
void UART1_config(u8 brt);
void PrintString1(u8 *puts);
//========================================================================
//=============串口单字节发送函数======================================
//========================================================================
void sendByte(u8 dat)
{
SBUF = dat;
B_TX1_Busy = 1;
while(B_TX1_Busy);
}
//========================================================================
//=============串口单字节序列发送函数======================================
//========================================================================
void sendByteArray(u8* dat,u8 len)
{
int i;
for(i=0;i<len;i++)
{
sendByte(dat);
}
}
//========================================================================
//=============串口命令发送函数======================================
//========================================================================
void send(u8 cmd,u8 len,u8* dat)
{
char head[4]={0};
head[0]=cmd;
head[1]=len/256/256;
head[2]=len/256%256;
head[3]=len%256;
sendByteArray(head,4);
sendByteArray(dat,len);
}
//=================串口时钟配置函数============================================
void SetTimer2Baudraye(u32 dat)
{
T2R = 0; //Timer stop
T2_CT = 0; //Timer2 set As Timer
T2x12 = 1; //Timer2 set as 1T mode
T2H = (u8)(dat / 256);
T2L = (u8)(dat % 256);
ET2 = 0;
T2R = 1; //Timer run enable
}
//==================串口配置=============================================
void UART1_config(u8 brt)
{
if(brt == 2)
{
S1BRT = 1; //S1 BRT Use Timer2;
SetTimer2Baudraye(Baudrate1);
}
else
{
TR1 = 0;
S1BRT = 0; //S1 BRT Use Timer1;
T1_CT = 0; //Timer1 set As Timer
T1x12 = 1; //Timer1 set as 1T mode
TMOD &= ~0x30;
TH1 = (u8)(Baudrate1 / 256);
TL1 = (u8)(Baudrate1 % 256);
ET1 = 0;
TR1 = 1;
}
/*************************************************/
SCON = (SCON & 0x3f) | 0x40;
// PS = 1;
ES = 1;
REN = 1;
P_SW1 &= 0x3f;
P_SW1 |= 0x40;
B_TX1_Busy = 0;
TX1_Cnt = 0;
RX1_Cnt = 0;
}
void UART1_rec_p2(u8 cmd,u8*dat,u8 len);
//========================================================================
//=============串口命令接收处理函数======================================
//========================================================================
void UART1_rec_p1(char* dat,int len)
{
static char* ctrl_data[50]={0};//接收的数据,声明被放在很前面,为了实现注册时无需复制
static unsigned char ctrl_cmd=0;//接收的命令
static unsigned char ctrl_sta=0; //目前状态,0为命令,1,2,3 为长度的高位到低位,4为数据
static u8 data_total_len=0,data_now_len=0;
int i,j;
for(i=0;i<len;i++)
{
if(ctrl_sta==0)
{
ctrl_cmd=dat;
data_total_len=0;
ctrl_sta++;
}
else if(ctrl_sta==4)
{
if((len-i)<(data_total_len-data_now_len))
{
for(j=i;j<len;j++)
{
ctrl_data[data_now_len+j-i]=dat[j];
}
data_now_len+=(len-i);
return;
}
else
{
for(j=data_now_len;j<data_total_len;j++)
{
ctrl_data[j]=dat[j-data_now_len+i];
}
i+=(data_total_len-data_now_len);
//收到指令+数据!
UART1_rec_p2(ctrl_cmd,ctrl_data,data_total_len);
ctrl_sta=0;
}
}
else
{
data_total_len*=256;
data_total_len+=dat;
ctrl_sta++;
if(ctrl_sta==4)
{
data_now_len=0;
if(data_total_len==0)
{
ctrl_sta=0;
//收到指令!
UART1_rec_p2(ctrl_cmd,ctrl_data,data_total_len);
}
}
}
}
}
//========================================================================
//=============串口命令处理函数======================================
//========================================================================
void UART1_rec_p2(u8 cmd,u8*dat,u8 len)
{
int i;
if(cmd==0x01)//保存透视矩阵
{
for(i=0;i<9;i++)
{
M=dat;
}
}
else if(cmd==0x02)//绕着A4矩形走
{
float x[4]={0};
float y[4]={0};
struct pointF in;
struct pointF out;
int i;
int cnt=0;
for(i=0;i<4;i++)
{
x=dat[4*i]*256+dat[4*i+1];
y=dat[4*i+2]*256+dat[4*i+3];
in.x=x;
in.y=y;
}
while(1)
{
cnt++;
if(cnt<200)
{
move((200-(cnt-0))*x[0]/200+(cnt-0)*x[1]/200,(200-(cnt-0))*y[0]/200+(cnt-0)*y[1]/200);
}
else if(cnt<400)
{
move((200-(cnt-200))*x[1]/200+(cnt-200)*x[2]/200,(200-(cnt-200))*y[1]/200+(cnt-200)*y[2]/200);
}
else if(cnt<600)
{
move((200-(cnt-400))*x[2]/200+(cnt-400)*x[3]/200,(200-(cnt-400))*y[2]/200+(cnt-400)*y[3]/200);
}
else if(cnt<800)
{
move((200-(cnt-600))*x[3]/200+(cnt-600)*x[0]/200,(200-(cnt-600))*y[3]/200+(cnt-600)*y[0]/200);
}
else
{
break;
}
usleep(25000);
}
}
}
void UART1_int (void) interrupt 4
{
u8 dat;
u16 d1=0,d2=0;
u8 sum;
int i;
if(RI)
{
dat=SBUF;
UART1_rec_p1(&dat,1);
RI = 0;
}
if(TI)
{
TI = 0;
B_TX1_Busy = 0;
}
}
void Delay10ms() //@35MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 10;
j = 85;
k = 113;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/******************************** 设置激光点位置函数 ************************************/
void move(float x,float y)
{
struct pointF p;
struct pointF rad;
struct pointI pwm;
p.x=x;
p.y=y;
rad= cor2rad(p);
pwm=rad2pwm(rad);
}
struct pointF cor2rad(struct pointF cor)
{
float phi,theta;
float x=cor.x,y=cor.y;
struct pointF res;
phi=atan(x);
theta=atan(y/(sqrt(x*x+1)) );
res.x=phi;
res.y=theta;
return res;
}
struct pointI rad2pwm(struct pointF rad)
{
const float k_phi=605.102;
const float k_theta=609.37;
float phi=rad.x;
float theta=rad.y;
struct pointI res;
int x,y;
x=8832+k_phi*phi;
y=8197-k_theta*theta;
res.x=x;
res.y=y;
return res;
}
/******************************** 激光点绕屏幕边框运动函数 ************************************/
void walk_panel(void)
{
static int cnt=0;
const float x[]={-0.28,0.25,0.225,-0.28};
const float y[]={0.52,0.525,0.03,0.025};
while(1)
{
if(cnt<200)
{
move((200-(cnt-0))*x[0]/200+(cnt-0)*x[1]/200,(200-(cnt-0))*y[0]/200+(cnt-0)*y[1]/200);
if(cnt==0)
{
Delay10ms();
}
}
else if(cnt<400)
{
move((200-(cnt-200))*x[1]/200+(cnt-200)*x[2]/200,(200-(cnt-200))*y[1]/200+(cnt-200)*y[2]/200);
}
else if(cnt<600)
{
move((200-(cnt-400))*x[2]/200+(cnt-400)*x[3]/200,(200-(cnt-400))*y[2]/200+(cnt-400)*y[3]/200);
}
else if(cnt<800)
{
move((200-(cnt-600))*x[3]/200+(cnt-600)*x[0]/200,(200-(cnt-600))*y[3]/200+(cnt-600)*y[0]/200);
}
else
{
break;
}
Delay10ms();
cnt++;
}
}
/******************************** 激光点回原点函数 ************************************/
void walk_home(void)
{
move(-0.01,0.25);
}
/******************************** 激光点A4靶标边框运动函数 ************************************/
void walk_A4_ai(void)
{
send(0x02,"",0);
}
/******************************** 透视变换函数 ************************************/
struct pointF cvt_point(struct pointI src)
{
int u = src.x;
int v = src.y;
struct pointF dst;
dst.x= (M[0*3+0]*u+M[0*3+1]*v+M[0*3+2])/(M[2*3+0]*u+M[2*3+1]*v+M[2*3+2]);
dst.y=(M[1*3+0]*u+M[1*3+1]*v+M[1*3+2])/(M[2*3+0]*u+M[2*3+1]*v+M[2*3+2]);
return dst;
}
/******************************** 五点校准函数 ************************************/
void corr(void)
{
int i;
float pos[]={-0.2,0.45,0.2,0.45,0.2,0.05,-0.2,0.05};
u8 dat[5]={0};
for(i=0;i<5;i++)
{
move(pos[2*i],pos[2*i+1]);
dat[0]=i;
dat[1]=(u16)(pos[2*i]*1000)/256;
dat[2]=(u16)(pos[2*i]*1000)%256;
dat[3]=(u16)(pos[2*i+1]*1000)/256;
dat[4]=(u16)(pos[2*i+1]*1000)%256;
send(0x01,dat,5);
}
}
/******************************** 主函数 ************************************/
void main(void)
{
unsigned long i=0;
unsigned long j=0;
char a[20]="is xxxx,and xx\r\n";
bit flag=0;
int cntb;
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
RSTFLAG |= 0x04; //设置硬件复位后需要检测P3.2的状态选择运行区域,否则硬件复位后进入USB下载模式
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0xFF; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
PWM5_Flag = 0;
PWM6_Flag = 0;
PWM5_Duty = 0;
PWM6_Duty = 12680;
PWMB_PSCRH=0x00;
PWMB_PSCRL=0X23;//700div
//-------------------------
PWMB_CCER1 = 0x00; //写 CCMRx 前必须先清零 CCxE 关闭通道
PWMB_CCER2 = 0x00;
PWMB_CCMR1 = 0x60; //通道模式配置
PWMB_CCMR2 = 0x60;
PWMB_CCMR3 = 0x60;
PWMB_CCMR4 = 0x60;
PWMB_CCER1 = 0x33; //配置通道输出使能和极性
PWMB_CCER2 = 0x33;
PWMB_ARRH = (u8)(PWM_PERIOD >> 8); //设置周期时间
PWMB_ARRL = (u8)PWM_PERIOD;
PWMB_ENO = 0x00;
PWMB_ENO |= ENO5P; //使能输出
PWMB_ENO |= ENO6P; //使能输出
PWMB_PS = 0x00; //高级 PWM 通道输出脚选择位
PWMB_PS |= PWM5_1; //选择 PWM5_1 通道
PWMB_PS |= PWM6_1; //选择 PWM6_1 通道
PWMB_BRK = 0x80; //使能主输出
PWMB_CR1 |= 0x01; //开始计时
EUSB = 1; //IE2相关的中断位操作使能后,需要重新设置EUSB
EA = 1; //打开总中断
UART1_config(2);
PWM5_Duty=0;
PWM6_Duty=0;
while (1)
{
Delay10ms();
if(P35==0)//校准
{
Delay10ms();
if(P35==0)
{
corr();
while(!P35);
}
}
if(P34==0)//回原点
{
Delay10ms();
if(P34==0)
{
walk_home();
while(!P34);
}
}
if(P33==0)//绕屏走
{
Delay10ms();
if(P33==0)
{
walk_panel();
while(!P33);
}
}
if(P32==0)//绕靶走
{
Delay10ms();
if(P32==0)
{
walk_A4_ai();
while(!P32);
}
}
}
}
void UpdatePwm(u16 pwm5,u16 pwm6)
{
if((pwm5!=PWM5_Duty) || (pwm6!=PWM6_Duty))
{
PWM5_Duty=pwm5;
PWM6_Duty=pwm6;
}
PWMB_CCR5H = (u8)(PWM5_Duty >> 8); //设置占空比时间
PWMB_CCR5L = (u8)(PWM5_Duty);
PWMB_CCR6H = (u8)(PWM6_Duty >> 8); //设置占空比时间
PWMB_CCR6L = (u8)(PWM6_Duty);
}
void delay_ms(u8 ms)
{
u16 i;
do{
i = MAIN_Fosc / 6000;
while(--i); //6T per loop
}while(--ms);
}
|
|