int main(void){ Stm32_Clock_Init(9); //系统时钟设置 uart_init(72,9600); //串口初始化为9600 delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 LCD_Init(); //初始化LCD usmart_dev.init(72); //初始化USMART BEEP_Init(); //蜂鸣器初始化 KEY_Init(); //按键初始化 TPAD_Init(72); //初始化TPAD FSMC_SRAM_Init(); //初始化外部SRAM mem_init(SRAMIN); //初始化内部内存池 mem_init(SRAMEX); //初始化外部内存池 tp_dev.init(); ucos_load_main_ui(); OSInit(); //初始化UCOSII OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务 OSStart(); } //开始任务void start_task(void *pdata){ OS_CPU_SR cpu_sr=0; u8 err; pdata = pdata; msg_key=OSMboxCreate((void*)0); //创建消息邮箱 q_msg=OSQCreate(&MsgGrp[0],256); //创建消息队列 flags_key=OSFlagCreate(0,&err); //创建信号量集 OSStatInit(); //初始化统计任务.这里会延时1秒钟左右 OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断) OSTaskCreate(led_task,(void *)0,(OS_STK*)&LED_TASK_STK[LED_STK_SIZE-1],LED_TASK_PRIO); OSTaskCreate(touch_task,(void *)0,(OS_STK*)&TOUCH_TASK_STK[TOUCH_STK_SIZE-1],TOUCH_TASK_PRIO); OSTaskCreate(qmsgshow_task,(void *)0,(OS_STK*)&QMSGSHOW_TASK_STK[QMSGSHOW_STK_SIZE-1],QMSGSHOW_TASK_PRIO); OSTaskCreate(main_task,(void *)0,(OS_STK*)&MAIN_TASK_STK[MAIN_STK_SIZE-1],MAIN_TASK_PRIO); OSTaskCreate(flags_task,(void *)0,(OS_STK*)&FLAGS_TASK_STK[FLAGS_STK_SIZE-1],FLAGS_TASK_PRIO); OSTaskCreate(key_task,(void *)0,(OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO); //挂起起始任务. OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)}//LED任务void led_task(void *pdata){ u8 t; while(1) { t++; delay_ms(10); if(t==8)LED0=1; //LED0灭 if(t==100) {t=0; LED0=0; } //LED0亮 } }//触摸屏任务void touch_task(void *pdata){ while(1) { tp_dev.scan(0); if(tp_dev.sta&TP_PRES_DOWN) //触摸屏被按下 { if(tp_dev.x
//得到角度//x,y,z:x,y,z方向的重力加速度分量(不需要单位,直接数值即可)//dir:要获得的角度.0,与Z轴的角度;1,与X轴的角度;2,与Y轴的角度.//返回值:角度值.单位0.1°.short ADXL345_Get_Angle(float x,float y,float z,u8 dir){ float temp,res=0; switch(dir) { case 0://与自然Z轴的角度 temp=sqrt((x*x+y*y))/z; res=atan(temp); break; case 1://与自然X轴的角度 temp=x/sqrt((y*y+z*z)); res=atan(temp); break; case 2://与自然Y轴的角度 temp=y/sqrt((x*x+z*z)); res=atan(temp); break; } return res*1800/3.14;} 该部分代码总共有8个函数,这里我们仅介绍其中4个。首先是ADXL345_Init函数,该函数用来初始化ADXL345,和前面我们提到的步骤差不多,不过本章我们而是采用查询的方式来读取数据的,所以在这里并没有开启中断。另外3个偏移寄存器,都默认设置为0。其次,我们介绍ADXL345_RD_XYZ函数,该函数用于从ADXL345读取数据,通过该函数可以读取ADXL345的转换结果,得到三个轴的加速度值(仅是数值,并没有转换单位)。接着,我们介绍ADXL345_AUTO_Adjust函数,该函数用于ADXL345的校准,ADXL345有偏移校准的功能,该功能的详细介绍请参考ADXL345数据手册的第29页,偏移校准部分。这里我们就不细说了,如果不进行校准的话,ADXL345的读数可能会有些偏差,通过校准,我们可以讲这个偏差减少甚至消除。最后,我们看看ADXL345_Get_Angle函数,该函数根据ADXL345的读值,转换为与自然坐标系的角度。计算公式如下:
其中Ax,Ay,Az分别代表从ADXL345读到的X,Y,Z方向的加速度值。通过该函数,我们只需要知道三个方向的加速度值,就可以将其转换为对应的弧度值,再通过弧度角度转换,就可以得到角度值了。其他函数,我们就不介绍了,也比较简单。保存adxl345.c,然后把该文件加入HARDWARE组下。接下来打开adxl345.h在该文件里面加入如下代码:#ifndef __ADXL345_H#define __ADXL345_H#include "myiic.h" #define DEVICE_ID 0X00 //器件ID,0XE5#define THRESH_TAP 0X1D //敲击阀值……省略部分寄存器定义#define FIFO_STATUS 0X39
//0X0B TO OX1F Factory Reserved //如果ALT ADDRESS脚(12脚)接地,IIC地址为0X53(不包含最低位).//如果接V3.3,则IIC地址为0X1D(不包含最低位).//开发板接V3.3,所以转为读写地址后,为0X3B和0X3A(如果接GND,则为0XA7和0XA6) #define ADXL_READ 0X3B#define ADXL_WRITE 0X3Au8 ADXL345_Init(void); //初始化ADXL345void ADXL345_WR_Reg(u8 addr,u8 val); //写ADXL345寄存器u8 ADXL345_RD_Reg(u8 addr); //读ADXL345寄存器void ADXL345_RD_XYZ(short *x,short *y,short *z); //读取一次值void ADXL345_RD_Avval(short *x,short *y,short *z); //读取平均值void ADXL345_AUTO_Adjust(char *xval,char *yval,char *zval); //自动校准void ADXL345_Read_Average(short *x,short *y,short *z,u8 times);//连续读取times次,取平均short ADXL345_Get_Angle(float x,float y,float z,u8 dir);#endif上面的代码省略了部分寄存器的定义,其他部分比较简单,我们不作介绍。保存adxl345.h,然后在test.c里面修改代码如下://x,y:开始显示的坐标位置//num:要显示的数据//mode:0,显示加速度值;1,显示角度值;void Adxl_Show_Num(u16 x,u16 y,short num,u8 mode){ if(mode==0) //显示加速度值 { if(num
30.3 软件设计 打开上一章的工程,首先在HARDWARE文件夹下新建一个CAN的文件夹,然后新建一个can.c和can.h的文件保存在CAN文件夹下,并将CAN文件夹加入头文件包含路径。打开can.c文件,输入如下代码:#include "can.h"#include "led.h"#include "delay.h"#include "usart.h"//CAN初始化//tsjw:重新同步跳跃时间单元.范围:1~3;//tbs2:时间段2的时间单元.范围:1~8;//tbs1:时间段1的时间单元.范围:1~16;//brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1//注意以上参数任何一个都不能设为0,否则会乱.//波特率=Fpclk1/((tbs1+tbs2+1)*brp);//mode:0,普通模式;1,回环模式;//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Normal_Init(1,8,7,5,1);//则波特率为:36M/((8+7+1)*5)=450Kbps//返回值:0,初始化OK;// 其他,初始化失败;u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode){ u16 i=0; if(tsjw==0||tbs2==0||tbs1==0||brp==0)return 1; tsjw-=1;//先减去1.再用于设置 tbs2-=1; tbs1-=1; brp-=1; RCC->APB2ENR|=1CRH|=0X000B8000;//PA11 RX,PA12 TX推挽输出 GPIOA->ODR|=3>16)&0XFF; dat[7]=(CAN->sFIFOMailBox[fifox].RDHR>>24)&0XFF; if(fifox==0)CAN->RF0R|=0X20;//释放FIFO0邮箱 else if(fifox==1)CAN->RF1R|=0X20;//释放FIFO1邮箱 }#if CAN_RX0_INT_ENABLE //使能RX0中断//中断服务函数 void USB_LP_CAN1_RX0_IRQHandler(void){ u8 rxbuf[8]; u32 id; u8 ide,rtr,len; Can_Rx_Msg(0,&id,&ide,&rtr,&len,rxbuf); printf("id:%d\r\n",id); printf("ide:%d\r\n",ide); printf("rtr:%d\r\n",rtr); printf("len:%d\r\n",len); printf("rxbuf[0]:%d\r\n",rxbuf[0]); printf("rxbuf[1]:%d\r\n",rxbuf[1]); printf("rxbuf[2]:%d\r\n",rxbuf[2]); printf("rxbuf[3]:%d\r\n",rxbuf[3]); printf("rxbuf[4]:%d\r\n",rxbuf[4]); printf("rxbuf[5]:%d\r\n",rxbuf[5]); printf("rxbuf[6]:%d\r\n",rxbuf[6]); printf("rxbuf[7]:%d\r\n",rxbuf[7]);}#endif
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧) //len:数据长度(最大为8) //msg:数据指针,最大为8个字节.//返回值:0,成功;// 其他,失败;u8 Can_Send_Msg(u8* msg,u8 len){ u8 mbox; u16 i=0; mbox=Can_Tx_Msg(0X12,0,0,len,msg); while((Can_Tx_Staus(mbox)!=0X07)&&(i=0XFFF)return 1; //发送失败? return 0; //发送成功;}//can口接收数据查询//buf:数据缓存区; //返回值:0,无数据被收到;// 其他,接收的数据长度;u8 Can_Receive_Msg(u8 *buf){ u32 id; u8 ide,rtr,len; if(Can_Msg_Pend(0)==0)return 0; //没有接收到数据,直接退出 Can_Rx_Msg(0,&id,&ide,&rtr,&len,buf); //读取数据 if(id!=0x12||ide!=0||rtr!=0)len=0; //接收错误 return len; }此部分代码总共8个函数,我们挑其中几个比较重要的函数简单介绍下,首先是:CAN_Mode_Init函数。该函数用于CAN的初始化,该函数带有5个参数,可以设置CAN通信的波特率和工作模式等,在该函数中,我们就是按30.1节末尾的介绍来初始化的,本章中,我们设计滤波器组0工作在32位标识符屏蔽模式,从设计值可以看出,该滤波器是不会对任何标识符进行过滤的,因为所有的标识符位都被设置成不需要关心,这样设计,主要是方便大家实验。 第二个函数,Can_Tx_Msg函数。该函数用于CAN报文的发送,该函数先查找空的发送邮箱,然后设置标识符ID等信息,最后写入数据长度和数据,并请求发送,实现一次报文的发送。 第三个函数,Can_Msg_Pend函数。该函数用于查询接收FIFOx(x=0/1)是否为空,如果返回0,则表示FIFOx空,如果为其他值,则表示FIFOx有数据。 第四个函数,Can_Rx_Msg函数。该函数用于CAN报文的接收,该函数先读取标识符,然后读取数据长度,并读取接收到的数据,最后释放邮箱数据。 can.c里面,还包含了中断接收的配置,通过can.h的CAN_RX0_INT_ENABLE宏定义,来配置是否使能中断接收,本章我们不开启中断接收的。其他函数我们就不一一介绍了,都比较简单,大家自行理解即可。保存can.c,并把该文件加入HARDWARE组下面,然后我们打开can.h在里面输入如下代码:#ifndef __CAN_H#define __CAN_H #include "sys.h" //CAN接收RX0中断使能#define CAN_RX0_INT_ENABLE 0 //0,不使能;1,使能. u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode); //CAN初始化u8 Can_Tx_Msg(u32 id,u8 ide,u8 rtr,u8 len,u8 *dat); //发送数据u8 Can_Msg_Pend(u8 fifox); //查询邮箱报文void Can_Rx_Msg(u8 fifox,u32 *id,u8 *ide,u8 *rtr,u8 *len,u8 *dat);//接收数据u8 Can_Tx_Staus(u8 mbox); //返回发送状态u8 Can_Send_Msg(u8* msg,u8 len); //发送数据u8 Can_Receive_Msg(u8 *buf); //接收数据#endif 其中CAN_RX0_INT_ENABLE用于设置是否使能中断接收,本章我们不用中断接收,故设置为0。保存can.h。最后,我们在test.c里面,修改main函数如下:int main(void){ u8 key; u8 i=0,t=0; u8 cnt=0; u8 canbuf[8]; u8 res; u8 mode=1;//CAN工作模式;0,普通模式;1,环回模式 Stm32_Clock_Init(9); //系统时钟设置 uart_init(72,9600); //串口初始化为9600 delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 LCD_Init(); //初始化LCD usmart_dev.init(72); //初始化USMART KEY_Init(); //按键初始化 CAN_Mode_Init(1,8,7,5,mode);//CAN初始化,波特率450Kbps POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(60,50,200,16,16,"WarShip STM32"); LCD_ShowString(60,70,200,16,16,"CAN TEST"); LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(60,110,200,16,16,"2012/9/11"); LCD_ShowString(60,130,200,16,16,"LoopBack Mode"); LCD_ShowString(60,150,200,16,16,"KEY0:Send WK_UP:Mode");//显示提示信息 POINT_COLOR=BLUE;//设置字体为蓝色 LCD_ShowString(60,170,200,16,16,"Count:"); //显示当前计数值 LCD_ShowString(60,190,200,16,16,"Send Data:"); //提示发送的数据 LCD_ShowString(60,250,200,16,16,"Receive Data:"); //提示接收到的数据 while(1) { key=KEY_Scan(0); if(key==KEY_RIGHT)//KEY0按下,发送一次数据 { for(i=0;i