发新帖本帖赏金 3.10元(功能说明)我要提问
123下一页
返回列表
打印

【MCU方案】基于MSP430F149 和 MSP430F425的简易智能电动车设计

[复制链接]
4654|50
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 hbzjt2011 于 2015-6-11 22:42 编辑

【MCU方案】基于MSP430F149 和 MSP430F425的简易智能电动车设计

功能介绍
         本小车以MSP超低功耗单片机系列MSP430F149和MSP430FE425为核心,完成寻迹、检测金属、避障、寻光、测速等功能。在机械结构上,对普通的小车作了改进,即用一个万用轮来代替两个前轮,使小车的转向更加灵敏。采用PWM 驱动芯片控制电机,红外传感器检测黑线,金属传感器检测铁片,光敏器件检测光强,红外 LED 和一体化接收头来避障。
方案描述
         【系统框图】
                本系统以 MSP430F149 和 MSP430F425 为控制核心。整个硬件框图如下图所示:

                          【主控模块】
                MSP430 系列单片机是美国TI公司1996 年开始推向市场的一种 16 位的超低功耗的混合信号处理器。其之所以称之为混合信号处理器,主要是由于其针对实际应用需求,把许多模拟电路、数字电路和微处理器集成在一个芯片上,以提供“单片”解决方案。MSP430 单片机更适合于低功耗、高速实时控制以及数据计算,它拥有更多的片上资源供设计使用,是设计的不错选择。 由于本小车实现功能较多, 因此我们选择了 MSP430F149 和 MSP430FE425为双核心的系统。通过编写通信协议,完成其之间的串行通信。
                其中MSP430F149 主要完成电机驱动、寻迹、避障、寻光等功能,MSP430FE425 主要完成金属检测、测速、液晶显示等功能。
         【电机驱动模块】   
                    电机的驱动芯片选用 L298N 作为驱动芯片。工作稳定电机驱动信号由单片机提供,信号经过光耦隔离后,传至 PWM 控制芯片 L298N,通过 L298N 的输出脚与两个电机相连。      
       【寻迹模块】
                 当小车在白色地面行驶时,装在车下的红外发射管发射红外线信号,经白色反射后,被接收管接收,一旦接收管接收到信号,输出端将输出低电平;当小车行驶到黑线时,红外线信号被黑色吸收后,将输出高电平,从而实现了通过红线检测信号的功能。将检测到的信号送到单片机的 I/O 口,当 I/O 口检测到的信号为高电平时,表明红外光被地上的黑线吸收了,表明小车处在黑色的引线上;同理,当 I/O 口检测到的信号为低电平时,表明小车行驶在白色地面上。                                 反射式红外传感器 ST188 采用高发射功率红外广电二极管和高灵敏度光电晶体管组成。检测距离可调整范围为 4-15mm;采用非接触检测方式。

        【金属检测模块】
                  采用市售的接近开关,无信号时,探头输出高电平。检测到金属时,电平跳变为低,单片机再进行相应处理。相应金属传感器型号为 LJ18A3 型。
          【寻光避障模块】
                  寻光避障模块均设计为环状传感器结构,共排布若干个传感器组,每个传感器组包含红外收发模块和光敏电阻。
                  光源检测模块,光敏电阻A组到E组从不同方向采光,每个光敏电阻的电压信号进入单片机片内ADC,利用F149系列内置的ADC12模块,实现了对五个方向光强的采集。由ADC的值,判断光强不同来确定小车的趋光方向;同理,可设定一个阈值比较,得出一开关信号调节最终小车停在车库内。 避障模块,利用单片机定时器发出可调制的 38KHz 红外线,利用一体化接收头判断,再由小车执行相应的避障动作。
        【测距和显示模块】
                  利用磁钢和干簧管,在车轮上均匀粘贴若干磁钢。每当车轮上磁钢转动至干簧管处,单片机进行一次计数,结合车轮半径就能求出小车行进距离。
                  显示模块采用段码液晶来实现, FE425 上有专门的液晶接口, 可以很方便地实现电路。液晶采用 4-MUX 输入方式的 7 位半段码液晶。
原理图
          主控板原理图及PCB:
         
          寻迹原理图及PCB:
           
           趋光避障原理图及PCB:
           

实物照片:




360截图20150611102843384.jpg (183.63 KB )

360截图20150611102843384.jpg

360截图20150611102937953.jpg (128.56 KB )

360截图20150611102937953.jpg

打赏榜单

liuxing4585 打赏了 0.10 元 2015-07-01

21ic小喇叭 打赏了 3.00 元 2015-06-15

相关帖子

沙发
hbzjt2011|  楼主 | 2015-6-11 11:01 | 只看该作者
源码程序:
          MSP430F149 程序:1、main.c
#include <msp430x14x.h>
#include "Sensor.h"
#include "Clock.h"
#include "dianji.h"
#include "Avoid.h"
#include "mean.h"
#include "ADC12.h"
#include "Uart.h"


Start()
{ int i;
for (i=0;i<=30000;i++);
}

void main(void)
{ WDTCTL = WDTPW + WDTHOLD;
BCS_Init();
TB_Init();
TimerAInit();
Init_PWM_Driver();
ADC12_Init();
InitSensor();
Port_Init();
UART_Init149();
Start();
_EINT();
while(1)
{
if(Flag_Stop == 0x01)
{
UART0_PutChar(0x08); //结束了
}
}
}
2、Sensor.c
#include <MSP430X14X.h>
#include "Clock.h"

//P1.1
#define PSEN14_H P1OUT |= (BIT1)
#define PSEN14_L P1OUT &= ~(BIT1)

//P1.2
#define PSEN25_H P1OUT |= (BIT2)
#define PSEN25_L P1OUT &= ~(BIT2)

//P1.3
#define PSEN36_H P1OUT |= (BIT3)
#define PSEN36_L P1OUT &= ~(BIT3)

/*
硬件上,5个IO口分别控制着5组传感器的电源
用宏定义把IO口置高置低预先定义好,用起来
方便,比如 PSEN14_H表示打开1号和4号传感器
的电源。PSEN14_L表示关闭1、4号传感器电源。
*/

#define SEN1_IN (P1IN & BIT4) /*P1.4*/
#define SEN2_IN (P2IN & BIT2) /*P2.2*/
#define SEN3_IN (P1IN & BIT6) /*P1.6*/
#define SEN4_IN (P1IN & BIT7) /*P1.7*/
#define SEN5_IN (P2IN & BIT0) /*P2.0*/
#define SEN6_IN (P2IN & BIT1) /*P2.1*/

//6只传感器的输入

#define P_coefficient 600
#define I_coefficient 0
#define D_coefficient 300
#define High_v 1000
#define Low_v 950
#define No_black 5000//找不到黑线时的转弯量控制
#define No_f_black 6000//前边找不到黑线时的转弯量控制

signed char Last_Position[10]; //声明数组,用于依次存放前5次的黑线位置。
unsigned char SensorData[6];//声明8个字节的数组,用于存放6个传感器读回值
signed int R_up=-600;//无黑线时初始旋转半径
signed int R_add=100;//旋转半径增加量

signed char Go_On_Black();
void Handle_No_Black();

void InitSensor() //初始化传感器
{
P1DIR |=(BIT1+BIT2+BIT3); //设为输出,控制传感器电源
//P4DIR |=(BIT0+BIT1); //BEEP P4.1 LED P4.0
//P4OUT &=~(BIT0 + BIT1);
}

void Beep_On()//LED,蜂鸣器函数,用定时器控制,不占用CPU
{ //int i;
// P4OUT |=BIT1; //蜂鸣器开始响
//P4OUT |= BIT0; //发光
//P4OUT |=BIT1;

}


signed char Caculate_Position(unsigned char *SensData) //计算黑线位置的函数
{
//由存有6个传感器输入值的数祖,计算黑线位置。
signed char i,j,SensorPosition;
for(i=0;i<6;i++) //从左往右数,
{
if(SensData[i]!=0) break; //找第一个读到黑线的传感器编号i
}
for(j=5;j>=0;j--) //从右往左数,
{
if(SensData[j]!=0) break; //找第一个读到黑线的传感器编号j
}
SensorPosition=(i+j)*10/2-25; //黑线中心位置就是(i+j)/2
//返回值为-25到+25
if(i==6) return(0x80); //如果全白(找不到黑线),就返回-128,作为出错标志。
return(SensorPosition); //将计算结果返回
}

signed char ReadSensor()//从传感器读取小车当前位置
{
unsigned char SensorData[6];//声明10个字节的数组,用于存放10个传感器读回值
signed char position;
unsigned char i;

PSEN14_H ; //打开1、4号传感器电源
Delay(32); //略延迟,等待数据稳定
SensorData[0]=SEN1_IN; //读1号传感器
SensorData[3]=SEN4_IN; //读4号传感器(注意数组下标从0开始,编号少1)
PSEN14_L ; //关闭1、4号传感器电源

PSEN25_H ; //打开2、5号传感器电源
Delay(32); //略延迟,等待数据稳定
SensorData[1]=SEN2_IN; //读2号传感器
SensorData[4]=SEN5_IN; //读5号传感器
PSEN25_L ; //关闭2、5号传感器电源

PSEN36_H ;
Delay(32);
SensorData[2]=SEN3_IN;
SensorData[5]=SEN6_IN;
PSEN36_L ;

//读取的6个传感器的状态,存入了SensorData[]里面
for(i=0;i<6;i++) //这样读回的数据,0表示白线,不为0的其他数据表示黑线
{ //为表示方便,将不为0的其他数据统统变成1
if(SensorData[i]==0)SensorData[i]=0;
else SensorData[i]=1; //黑线对应的数组单元存1;白线存0。
}
position=Caculate_Position(SensorData);//调用Caculate_Position()函数,计算黑线位置
return(position); //将黑线位置的计算结果返回
}

/*PID(PD)控制算法*/
int PID_Control(signed char Position)
{
//PID算法。这里只用了P和D。
int Temp_P,Temp_D,Temp_PID,Temp_I,k; //声明三个变量,用于存放P、I、D三分量的运算结果(I没用上)
if(Position==-128) return (No_black); //错误处理(值得改进的地方)
else
{
Temp_I=Position;
for(k=0;k<5;k++)Temp_I+=Last_Position[k];
Temp_I*=I_coefficient;
Temp_P=P_coefficient*Position; //计算比例分量(P)=比例系数*本次位置差
Temp_D=D_coefficient*(Position-Last_Position[5]); //计算微分分量(D)=微分系数*(本次位置差-前3次的位置差)
//注意由于采样比较快,用本次位置-前3次位置才有足够大的控制量
Last_Position[9]=Last_Position[8];
Last_Position[8]=Last_Position[7];
Last_Position[7]=Last_Position[6];
Last_Position[6]=Last_Position[5];
Last_Position[4]=Last_Position[3]; //微分量会把随机噪音放大,如果采样间隔太小,得到的几乎全是噪音
Last_Position[3]=Last_Position[2]; //如果单纯加大采样间隔,比例环节采样也会间隔加大,控制精度难以保证
Last_Position[2]=Last_Position[1]; //所以采样还是用较高速采样,微分环节采用本次- 前K次的方法降低采样速率。
Last_Position[1]=Last_Position[0]; /*这种方法还有一定的滤波降噪效果(同学们自己推算一下)。标准的实用PID程序微分环节前还要有一次滤波,这里就省去了(本次-前K次就是简易的均值虑波)。*/
Last_Position[0]=Position; /*保存前5次的位置,以备用。同学们可以试验一下改变K值的效果,自己摸索最佳值。 */
Temp_PID=Temp_P+Temp_D+Temp_I; //P分量和D分量相加,得到控制量。
if(Temp_PID>5000) Temp_PID=5000; //防止控制量溢出
if(Temp_PID<-5000) Temp_PID=-5000; //控制量-2500~2500作为左右满舵
Temp_PID=Temp_PID*1/5; //-1000~+1000是左右满舵的输出,因此需要除以0.5
/*单片机浮点运算非常慢,所以用乘2除5两次定点运算来替代定点数要先乘后除,才能保证精度,同时要防止溢出,用起来比较麻烦,但CPU和内存开销小。*/
return (Temp_PID);
}
}

//右电机由CCR2,CCR3控制,CCR2高时为正转
//左电机右CCR4,CCR5控制,CCR4高时为正转
/*设置小车转弯量*/
void Set_Rotation (int Rotation)
//用-1000~+1000表示左转满舵~右转满舵
{
//if(Rotation==No_black)
//Handle_No_Black();
//else
if(Rotation>0) //Rotation大于0是右转,
{
TBCCR2=High_v; //右轮减速,
TBCCR3=0;
TBCCR4=High_v-Rotation; //左轮全速前进,
TBCCR5=0;
}
else //Rotation小于0是左转
{
TBCCR4=High_v; //左轮减速(注意Rotation是负值,加运算就是减速)
TBCCR5=0;
TBCCR3=0;
TBCCR2=High_v+Rotation; //左轮全速

}

}


/*错误处理 */
void Handle_No_Black()
{
signed int j;
signed char L_l,L_r;
L_l=Last_Position[0];
L_r=Last_Position[9];
Last_Position[0]=0;Last_Position[1]=0;Last_Position[2]=0;Last_Position[3]=0;Last_Position[4]=0;
Last_Position[5]=0;Last_Position[6]=0;Last_Position[7]=0;Last_Position[8]=0;Last_Position[9]=0;
if(L_l<=L_r)
{
TBCCR4=High_v-30; //右轮全速前进
TBCCR5=0;
for(;R_up<=High_v;)
{
if(R_up<0)
{
TBCCR2=0;
TBCCR3=-R_up; //左轮减速
R_up+=(2*R_add);
}
else
{
TBCCR2=R_up;
TBCCR3=0; //左轮减速
R_up+=R_add;
}
if(R_up>High_v){R_up=-600;break;}
for(j=0;j<(700+R_up)/2;j++)
{
if(Go_On_Black()==5)continue;
else break;
}
if(Go_On_Black()==5)continue;
else break;
}
}
else
{
TBCCR2=High_v; //左轮全速前进
TBCCR3=0;
for(;R_up<=High_v;)
{
if(R_up<0)
{
TBCCR5=-R_up;
TBCCR4=0; //右轮减速
R_up+=(2*R_add);
}
else
{
TBCCR5=0;
TBCCR4=R_up; //右轮减速
R_up+=R_add;
}
if(R_up>High_v){R_up=-600;break;}
//for(j=0;j<(700+R_up)/2;j++)
//{
// if(Go_On_Black()==5)continue;
//else break;
// }
//if(Go_On_Black()==5)continue;
else break;
}
}
R_up=-600;
}

signed char Go_On_Black()
{
signed char left;
PSEN14_H ; //打开1、4号传感器电源
Delay(30); //略延迟,等待数据稳定
SensorData[0]=SEN1_IN;
SensorData[3]=SEN4_IN; //读4号传感器(注意数组下标从0开始,编号少1)
PSEN14_L ; //关闭1、4号传感器电源

PSEN25_H ; //打开2、5号传感器电源
Delay(30); //略延迟,等待数据稳定
SensorData[1]=SEN2_IN; //读2号传感器
SensorData[4]=SEN5_IN; //读5号传感器
PSEN25_L; //关闭2、4号传感器电源

PSEN36_H ; //打开3号传感器电源
Delay(30); //略延迟,等待数据稳定
SensorData[2]=SEN3_IN; //读3号传感器
SensorData[5]=SEN5_IN;
PSEN36_L ; //关闭3号传感器
for (left=0;left<=5;left++)
{
if (SensorData[left]!=0) break; //找第一个读到黑线的传感器编号i
}
return left;
}
3、Clock.c
#ifndef _Clock_h
#define _Clock_h
//Clock.c
#include "MSP430x14x.h"
#include "Sensor.h"
#include "Avoid.h"
#include "Uart.h"
#include "dianji.h"
#include "mean.h"
#include "ADC12.h"

unsigned int Parking5s=0;
unsigned char Flag_Parking=0;
unsigned long int interrupt_time1=0x00;
unsigned long int interrupt_time2=0x00;
int Rotation;
signed char Position;


// XT2高频晶振2失效标志检查
void XT2_Init(void)
{
unsigned char i;
BCSCTL1 &= ~(XT2OFF);
do{
IFG1 &= ~(OFIFG);
for(i=0; i<100; i++)
{
_NOP();
}
}
while((IFG1 & OFIFG) != 0);
}

// 系统时钟初始化
void BCS_Init(void)
{
XT2_Init();
BCSCTL1 = DIVA_0 + RSEL0+ RSEL1 + RSEL2;//XT2开,XT1低频模式,高匹配电阻
BCSCTL2 = SELM_2 + DIVM_0 + SELS + DIVS_0;//MCLK SMCLK选择XT2,不分频
}


void TimerAInit()
{ //设置数组,对应频率分别为38,41,44,48,54,60,67
TACTL |= TASSEL_2 + TACLR + MC_1 ; //TIMER_A时钟源选为SMCLK,清TAR
TACCR0 = 44; //产生约38KHZ的PWM输出,SMCLK=4M,105个时钟周期
TACCTL0 |= OUTMOD_4; //翻转模式产生占空比为50%的PWM
P1DIR |= BIT5; //从P1.5输出
P1SEL |= BIT5;
TACCR1=40; //10us中断一次
TACCR2=40;
TACCTL1|=CCIE; //两个中断,一个用于走黑线,一个避障,其它地方再打开
TACCTL2&=~CCIE;

}

void Delay(unsigned char Time) //延迟程序
{
unsigned int i,k;
for(k=0;k<Time;k++)
for(i=0;i<Time;i++);
}




// TBCCO 中断服务
#pragma vector = TIMERB0_VECTOR
__interrupt void TBCC0_IRQ(void)
{ // unsigned char i;
if(Flag_Parking == 1)
Parking5s++;
UART0_GetChar(Command);
if(Command[0]==0x01)
{
//Delay5s();
P4DIR|=BIT1;
P4OUT&=~BIT1;
Delay(100);
P4OUT|=BIT1;
Command[0]=0;
}
if(Command[0]==0x02) //02为检测到第三块时的停车命令,然后149自己延时5s
{
TACCTL1&=~CCIE;
TACCTL2&=~CCIE;
Flag_Parking =1;
P4DIR|=BIT0;
P4OUT|=BIT0;
P4OUT|=BIT1;
P4OUT&=~BIT1;
Delay(100);
P4OUT|=BIT1;
//延时五秒函数
Stop();

//TACCTL1&=~CCIE; //Unenable interrupt
//TACCTL2&=~CCIE;

Command[0]=0;
//
}
if(Flag_Stop == 0x01)
{
TACCTL1&= ~CCIE; //Unenable interrupt
TACCTL2&= ~CCIE;
Stop();

//for(i=0;i<5;i++)

}
if(Parking5s == 160)
{TACCTL2|=CCIE;
P4OUT&=~BIT0;
P4OUT&=~BIT1;
Delay(100);
P4OUT|=BIT1;
Flag_Parking = 0;
Parking5s++;
}
}

void TB_Init(void)
{
TBCTL = TBSSEL_1 + TBCLR + ID_0 + MC_0;
TBCCR0 = 1024;
TBCTL = TBSSEL_1 + TBCLR + ID_0 + MC_1;
TBCCTL0 |= CCIE;

}

#pragma vector=TIMERA1_VECTOR //节拍控制
__interrupt void Timer_A(void)
{
switch(TAIV)
{
case 2: interrupt_time1++;if(interrupt_time1==1000){Position=ReadSensor();// 检测黑线,计算位置
Rotation=PID_Control(Position); // PID控制算法
Set_Rotation(Rotation);//设置小车转弯量
interrupt_time1=0x00;
}
break;
case 4: interrupt_time2++;if(interrupt_time2==1000){ADC12_Deal();
Measure_Light();
Measure_Distance();
FSM();
//Find_Light();
interrupt_time2=0x00;}
break;
default: break;
}
}


void Interrupt_Stop()
{
TACCTL1&= ~CCIE; //Unenable interrupt
TACCTL2&= ~CCIE;
}

#endif
4、dianji.c
//右电机由CCR2,CCR3控制,CCR2高时为正转
//左电机右CCR4,CCR5控制,CCR4高时为正转
//线的顺序白,黑,绿,黄
#include <msp430x14x.h>
#include "dianji.h"
#include "Clock.h"
void Init_PWM_Driver() // 初始化电机驱动电路
{
P4DIR |=BIT6; //p4.6为使能端ENA
P4DIR |=BIT7; //p4.7为使能端ENB
P4OUT |=BIT6;
P4OUT |=BIT7;
P4DIR |=BIT5+BIT2+BIT3+BIT4;
P4SEL |=BIT5+BIT2+BIT3+BIT4;
TBCCTL2 |= OUTMOD_7;//TBCCR2输出为模式7,RESET/SET
TBCCR2 =0; //P4.2口输出TB1__L1
TBCCTL3 |= OUTMOD_7; //TBCCR2输出为模式7,SET/RESET
TBCCR3 =0; //P4.3口输出TB2__L2
TBCCTL4 |= OUTMOD_7; //TBCCR4输出为模式7,RESET/SET
TBCCR4 =0; //P4.4口输出TB3__R2
TBCCTL5 |= OUTMOD_7; //TBCCR5输出为模式7,RESET/SET
TBCCR5 =0; //P4.5口输出TB4__R1
TBCTL |= MC_1; //TIMER_B工作于增计数方式
}

/*转弯部分*/
void Turn_Left() //左转函数
{TBCCR2=0;
TBCCR3=0;
TBCCR4=1000;
TBCCR5=0;
}
void Turn_Right()//右转函数
{TBCCR2=1000;
TBCCR3=0;
TBCCR4=0;
TBCCR5=0;

}
void Turn_Normal()//直行函数
{TBCCR2=1000;
TBCCR3=0;
TBCCR4=1000;
TBCCR5=0;
}

void Turn_Back()//直退函数
{TBCCR2=0;
TBCCR3=1000;
TBCCR4=0;
TBCCR5=1000;
}

void Stop()//停止函数
{TBCCR5=0;
TBCCR2=0;
TBCCR3=0;
TBCCR4=0;
}

void Test()//测试运行
{ int i = 0;
Turn_Right();
for(i=0;i<100;i++)
Delay(100);

Turn_Left();
for(i=0;i<100;i++)
Delay(100);

//Turn_Back();

}


使用特权

评论回复
板凳
hbzjt2011|  楼主 | 2015-6-11 11:01 | 只看该作者
5、Avoid.c

#include <msp430x14x.h>
#include "avoid.h"
#include "dianji.h"
#include "Clock.h"
#include "mean.h"

#define Obstacle 300 //避障权值大于光强

unsigned char Status = 0; //寻光,避障选择初始状态设为0
#define Light_Status 1 //寻光状态为1
#define Barrier_Status 2 //避障状态为2

static unsigned char BarrierData[5]={0,0,0,0,0}; // 用来表记是否检测到障碍物,若有则置1;否则就清零
static unsigned char flag = 0;//障碍标志

unsigned int cnt = 0;

void Port_Init()
{
P2DIR |= BIT7 + BIT6 +BIT5 + BIT4+ BIT3;
P2OUT |= BIT7 + BIT6 +BIT5 + BIT4+ BIT3;
}


/*测障碍物*/
//BarrierData的值离障碍物越近,数值越大,5是距离最近的,为0说明没有检测到
void Measure_Distance()
{
unsigned char flag_1=0,flag_2=0,flag_3=0,flag_4=0,flag_0=0;
//unsigned char i,Frequency[5] = {29,36,44,47,51}; //66,54,44,42,38
// 1
if(flag_0==0)
{
Delay(34);
PIRE1_H; // 打开1号传感器
Delay(34); // 延迟,等待数据稳定
if(IRE1_IN==0) // 如果接收到的信号为低电平,表明前方有障碍物
{flag_0 = 1;BarrierData[0]=1;}
else BarrierData[0]=0;
PIRE1_L;
}
//2
if(flag_1==0)
{
Delay(34);
PIRE2_H; // 打开2号传感器
Delay(34); // 延迟,等待数据稳定
if(IRE1_IN==0) // 如果接收到的信号为低电平,表明前方有障碍物
{flag_1 = 1;BarrierData[1]=1;}
else BarrierData[1]=0;
PIRE2_L;
}
// 3
if(flag_2==0)
{
PIRE3_H ; // 打开3号传感器    
Delay(34); // 延迟,等待数据稳定


if(IRE3_IN==0) // 如果接收到的信号为低电平,表明右前方有障碍物
{flag_2 = 1;BarrierData[2]=1;}
else {BarrierData[2]=0;}
PIRE3_L;
// 关闭3号传感器
}
// 4

if(flag_3==0)
{
PIRE4_H ; // 打开4号传感器    
Delay(34); // 延迟,等待数据稳定

if(IRE4_IN==0) // 如果接收到的信号为低电平,表明右前方有障碍物
{flag_3 = 1;BarrierData[3]=1;}
else BarrierData[3]=0;
PIRE4_L; // 关闭4号传感器
}
// 5
if(flag_4==0)
{
Delay(34);
PIRE5_H ; // 打开5号传感器    
Delay(34); // 延迟,等待数据稳定

if(IRE5_IN==0) // 如果接收到的信号为低电平,表明右前方有障碍物
{flag_4 = 1;BarrierData[4]=1;}
else BarrierData[4]=0;
PIRE5_L; // 关闭5号传感器
}

if(flag_0||flag_1||flag_2||flag_3||flag_4) //寻光与避障的切换
{Status=2;flag=1;}
else Status=Light_Status; //寻光
}


//

void Avoid_Obstacle()//采用矢量合成,与寻光不同,避障的推力为负,所以坐标取反
{ if(flag == 1)
{
if((BarrierData[3]+BarrierData[4])>0) //
{
Turn_Left();
}
else if((BarrierData[0]+BarrierData[1])>0)//右边没有障碍
{
Turn_Right();
}
else
{
Turn_Left();
}

}
else
{
Turn_Normal();
}
}

void FSM()
{ //Find_Light();
switch (Status)
{case Light_Status : Find_Light(); break;
case Barrier_Status : Avoid_Obstacle(); break;
default: break;
}

}

//避障矢量合成的备份
/*void Avoid_Obstacle()//采用矢量合成,与寻光不同,避障的推力为负,所以坐标取反
{ if(flag == 0) return;

else
{
//1号红外,X轴正向,Y为0
x=x+Barrier[0]*BarrierData[0];
//2号,X为正,Y为负,45°
x=x+707*Barrier[1]*BarrierData[1]/1000;
y=y-707*Barrier[1]*BarrierData[1]/1000;
//3号,X为0,Y为负
y=y-Barrier[2]*BarrierData[2];
//4号,X为负,Y为负,45°
x=x-707*Barrier[3]*BarrierData[3]/1000;
y=y-707*Barrier[3]*BarrierData[3]/1000;
//5号,Y为0,X为负
x=x-Barrier[4]*BarrierData[4];
}
if (flag_ahead==0) y=1000;
}
*/

/*带45°处理备份
void Avoid_Obstacle()//采用矢量合成,与寻光不同,避障的推力为负,所以坐标取反
{ if(flag == 1)
{
if((BarrierData[0]==0)&&(BarrierData[1]==0))//左边没有障碍
{
Turn_Left();
}
else
{
if((BarrierData[4]==0)&&(BarrierData[3]==0))//右边没有障碍
{
Turn_Right();
}
else
{
Turn_Back();
}
}
}
else
{
Turn_Normal();
}
}
*/
6、mean.c
#include <msp430x14x.h>
#include "ADC12.h"
#include "Clock.h"
#include "dianji.h"
#define Intensity 150 //光强权值


unsigned char Light[5]; //定义归一化光强值
signed long int x=0,y=0; //调CCRx值时候的参数
signed long int XY;
unsigned char Flag_Stop;

void Measure_Light()
{ //归一化光强,从0-4906分为25档,
unsigned char i;
unsigned char Minimum;//记录最小光强
for(i=0;i<5;i++)
{ if(AccessResult[i]<200) Light[i]=25;
else if(AccessResult[i]<400) Light[i]=24;
else if(AccessResult[i]<600) Light[i]=23;
else if(AccessResult[i]<800) Light[i]=22;
else if(AccessResult[i]<1000) Light[i]=21;
else if(AccessResult[i]<1200) Light[i]=20;
else if(AccessResult[i]<1400) Light[i]=19;
else if(AccessResult[i]<1600) Light[i]=18;
else if(AccessResult[i]<1800) Light[i]=17;
else if(AccessResult[i]<2000) Light[i]=16;
else if(AccessResult[i]<2200) Light[i]=15;
else if(AccessResult[i]<2400) Light[i]=14;
else if(AccessResult[i]<2600) Light[i]=13;
else if(AccessResult[i]<2800) Light[i]=12;
else if(AccessResult[i]<3000) Light[i]=11;
else if(AccessResult[i]<3200) Light[i]=10;
else if(AccessResult[i]<3400) Light[i]=9;
else if(AccessResult[i]<3600) Light[i]=8;
else if(AccessResult[i]<3800) Light[i]=7;
else if(AccessResult[i]<4000) Light[i]=6;
else if(AccessResult[i]<4200) Light[i]=5;
else if(AccessResult[i]<4400) Light[i]=4;
else if(AccessResult[i]<4600) Light[i]=3;
else if(AccessResult[i]<4800) Light[i]=2;
else if(AccessResult[i]<4096) Light[i]=1;
else Light[i]=0;
}
if((AccessResult[2]<=250)||((AccessResult[0]<=250))||(AccessResult[1]<=250))
{Flag_Stop = 1;

}
Minimum = Light[0];
for(i=1;i<5;i++)
{ if(Minimum > Light[i])
Minimum = Light[i];
}
for(i=0;i<5;i++)
Light[i] = Light[i] - Minimum;

//矢量合成,X,Y两个轴,
x=0;
y=0;
//1号光敏电阻,无Y轴,X为负
x=x-Intensity*Light[0];

//2号光敏电阻,X为-0.707,Y为0.707,45度
x=x-(Intensity *Light[1]*707)/1000;
y=y+(Intensity *Light[1]*707)/1000;
//3号光敏电阻,X为0,Y为正

y=y+Intensity * Light[2];
//4号光敏电阻,X,Y都为+0.707,45度
x=x+(Intensity*Light[3]*707)/1000;
y=y+(Intensity*Light[3]*707)/1000;
//5号光敏电阻,Y为0,X为正
x=x+Intensity*Light[4];
y=y;
if(x>1000) x=1000;
if(y>1000) y=1000;
if(x<-1000) x=-1000;

}

//寻光控制运动函数
/*
void Find_Light()
{ int XY; //防止越界
if (y<0) y=0;
if (x>0) //右转,y为共同速度
{ if(x+y>1000)
XY = 1000;
else
{XY = x+y;}
TBCCR4=y;
TBCCR5=0;
TBCCR3=0;
TBCCR2=XY;
}
if(x<0) //左转
{ x = -x;
; if(x+y>1000)
XY = 1000;
else
XY = x+y;
TBCCR4=XY;
TBCCR5=0;
TBCCR3=0;
TBCCR2=y;
}

}
*/
//备份
//寻光控制运动函数
void Find_Light()
{ int XY; //防止越界
if (y<0) y=0;
if (x>0) //右转,y为共同速度
{ if(x+y/4>1000)
XY = 1000;
else
{XY = x+y/3;}
TBCCR4=(y/2); //1.10 8:15把Y从y/3改为y/2
TBCCR5=0;
TBCCR3=0;
TBCCR2=XY;
}
if(x<0) //左转
{ x = -x;
; if(x+y/4>1000)
XY = 1000;
else
{XY = x+y/3;}
TBCCR4=XY;
TBCCR5=0;
TBCCR3=0;
TBCCR2=(y/2);
}
}

7、ADC12.c
#include "msp430x14x.h"



#define RESISTANCE_SAMPLING (100) // 采样电阻, 单位:欧姆
#define VOLTAGE_REF (2500) // 参考电压, 单位:10毫伏+
#define MAX_SAMPLE_TIMES (5) //最大采样次数

unsigned int Cnt_ADC12;
unsigned long int Sum_results[8];
unsigned int results[8]; //转换结果临时寄存器
unsigned int AccessResult[9];
unsigned char TransmitResult[16];
unsigned char FLAG_END = 0;



void ADC12_Init(void)
{ unsigned char i;
P6SEL |= 0xff; //设置P6为模拟输入通道
ADC12CTL0 = ADC12ON + MSC + SHT0_2 + REF2_5V + REFON;
ADC12CTL1 = CSTARTADD_0 + ADC12SSEL_0 + SHP + CONSEQ_1 ; //序列通道单次转换模式
ADC12MCTL0 = SREF_1 + INCH_0 ; //通道A0参考电压:V+=Vref+,V-=AVss
ADC12MCTL1 = SREF_1 + INCH_1 ; //通道A1
ADC12MCTL2 = SREF_1 + INCH_2 ; //通道A2
ADC12MCTL3 = SREF_1 + INCH_3 ; //通道A3
ADC12MCTL4 = SREF_1 + INCH_4+ EOS ; //通道A4
//ADC12MCTL5 = SREF_1 + INCH_5 ; //通道A5
//ADC12MCTL6 = SREF_1 + INCH_6 ; //通道A6
//ADC12MCTL7 = SREF_1 + INCH_7 ; //通道A7,最后序列
ADC12IE = 0x10 ; //使能中断ADC12IFG.7
//ADC12CTL0 |= ENC ; //使能转换
for (i=0;i<5;i++)
AccessResult[i]=0xff;
}



void ADC12_Deal(void)
{
ADC12CTL0 |= ADC12SC + ENC; //开始转换
}



#pragma vector = ADC_VECTOR
__interrupt void ADC12_IRQ(void)
{

ADC12CTL0 &= ~ENC ; //关闭转换
Cnt_ADC12++ ;
results[0] = ADC12MEM0 ; //存结果,清除IFG
results[1] = ADC12MEM1 ;
results[2] = ADC12MEM2 ;
results[3] = ADC12MEM3 ;
results[4] = ADC12MEM4 ;
//results[5] = ADC12MEM5 ;
//results[6] = ADC12MEM6 ;
//results[7] = ADC12MEM7 ;
if( Cnt_ADC12 >= (MAX_SAMPLE_TIMES+1) )
{
Cnt_ADC12=1;
Sum_results[0] = 0;
Sum_results[1] = 0;
Sum_results[2] = 0;
Sum_results[3] = 0;
Sum_results[4] = 0;
//Sum_results[5] = 0;
//Sum_results[6] = 0;
//Sum_results[7] = 0;
}
if (Cnt_ADC12 <= MAX_SAMPLE_TIMES)
{

Sum_results[0] += results[0];
Sum_results[1] += results[1];
Sum_results[2] += results[2];
Sum_results[3] += results[3];
Sum_results[4] += results[4];
// Sum_results[5] += results[5];
//Sum_results[6] += results[6];
//Sum_results[7] += results[7];
}
if (Cnt_ADC12 == MAX_SAMPLE_TIMES)
{
AccessResult[0] = Sum_results[0] / MAX_SAMPLE_TIMES;
AccessResult[1] = Sum_results[1] / MAX_SAMPLE_TIMES;
AccessResult[2] = Sum_results[2] / MAX_SAMPLE_TIMES;
AccessResult[3] = Sum_results[3] / MAX_SAMPLE_TIMES;
AccessResult[4] = Sum_results[4] / MAX_SAMPLE_TIMES;
//AccessResult[5] = Sum_results[5] / MAX_SAMPLE_TIMES;
//AccessResult[6] = Sum_results[6] / MAX_SAMPLE_TIMES;
//AccessResult[7] = Sum_results[7] / MAX_SAMPLE_TIMES;
}

}
8、Uart.c
#include <msp430x14x.h>
#define RXBUF_SIZE 32
#define TXBUF_SIZE 32 //发送FIFO的最大容量

unsigned char RX_BUFF[RXBUF_SIZE];
unsigned int UART_InpLen = 0;
unsigned int RX_IndexR = 0;
unsigned int RX_IndexW = 0;
unsigned char TX_BUFF[TXBUF_SIZE]; //发送FIFO缓冲区数据
unsigned int UART_OutLen=0; //发送FIFO内等待发出的字节数
unsigned int TX_IndexR=0; //发送FIFO的读指针
unsigned int TX_IndexW=0; //发送FIFO的写指针
unsigned char Command[10];

//149串口初始化
UART_Init149()
{
U0CTL |= CHAR; //异步通讯模式,8位数据,无校验,1位停止位
ME1 |= UTXE0 + URXE0; //开启串口0收发模块
U0TCTL |= SSEL0; //选择ACLK作为串口波特率时钟源
U0BR1 = 0; //
U0BR0 = 13; //分频系数整数部分=13
U0MCTL = 0X6B; //分频系数小数部分调制=5/8.(2400bps)
P3SEL |= BIT4 + BIT5;
U0CTL &=~ SWRST; //启动串口
IE1 |= URXIE0;
}

UART_Init425()
{
U0CTL |= CHAR; //异步通讯模式,8位数据,无校验,1位停止位
ME1 |= UTXE0 + URXE0; //开启串口0收发模块
U0TCTL |= SSEL0; //选择ACLK作为串口波特率时钟源
U0BR1 = 0; //
U0BR0 = 13; //分频系数整数部分=13
U0MCTL = 0X6B; //分频系数小数部分调制=5/8.(2400bps)
P2SEL |= BIT4 + BIT5; //
U0CTL &=~ SWRST; //启动串口
IE1 |= URXIE0;
}

/*********************************************************
名称: UART0_GetChar()
功能: 从串口读一个字节数据
入口参数: 数据存放的地址指针
出口参数: 0表示失败,1表示成功
说明: 读取过程不阻塞CPU运行
*********************************************************/

char UART0_GetChar(unsigned char *Chr)
{
if(UART_InpLen == 0) return (0);
_DINT();
UART_InpLen--;
*Chr = RX_BUFF[RX_IndexR];
if (++RX_IndexR >= RXBUF_SIZE)
{ RX_IndexR = 0;
}
_EINT();
return (1);
}

/*********************************************************
名称: UART0_GetCharsInRxBuf()
功能:
入口参数:
出口参数: 待读取的字节数
*********************************************************/
unsigned int UART0_GetCharsInRxBuf()
{
return (UART_InpLen);
}
/*********************************************************
名称: UART0_ClrRxBuf()
功能: 清除接收队列
入口参数:
出口参数:
*********************************************************/

void UART0_ClrRxBuf()
{
_DINT();
UART_InpLen = 0;
RX_IndexR = 0;
RX_IndexW = 0;
_EINT();
}

//串口接收中断
#pragma vector= UART0RX_VECTOR
__interrupt void UART0_RX (void)
{
UART_InpLen ++;
RX_BUFF[RX_IndexW] =U0RXBUF;
if (++RX_IndexW >= RXBUF_SIZE)
{
RX_IndexW = 0;
}
}

/********************************************************************
名称:char UART0_PutChar()
功能:向串口发送一字节
入口参数: Chr,待发字节
出口参数: 返回1成功,0失败
********************************************************************/
char UART0_PutChar(unsigned char Chr)
{
if(UART_OutLen == TXBUF_SIZE)
{
return(0);
}
if(UART_OutLen == 0)
{
IFG1 |= UTXIFG0;
}
_DINT();
UART_OutLen++;
TX_BUFF[TX_IndexW] = Chr;
if (++TX_IndexW >= TXBUF_SIZE)
{
TX_IndexW = 0;
}
IE1 |= UTXIE0;
_EINT();
return (1);
}


//串口发送中断
#pragma vector=UART0TX_VECTOR
__interrupt void UART0_TX (void)
{
if(UART_OutLen>0)
{
UART_OutLen--;
U0TXBUF = TX_BUFF[TX_IndexR];
if(++TX_IndexR >= TXBUF_SIZE)
{
TX_IndexR = 0;
}
}
else IE1 &=~ UTXIE0;
}


使用特权

评论回复
地板
hbzjt2011|  楼主 | 2015-6-11 11:03 | 只看该作者
MSP430F149 程序:
1、main.c
#include "msp430x42x.h"
#include "RTC.h"
#include "BasicTimer.h"
#include "LCD_Display.h"
#include "Key.h"
#include "jinshu.h"
#include "UART.h"
char Hour;
char Minute;
char Second;
unsigned char Command149[5];

void main( void )
{
WDTCTL=WDTPW+WDTHOLD; //停止看门狗
FLL_CTL0|=XCAP18PF;         //配置晶振负载电容
//P1DIR|=BIT0+BIT1+BIT2+BIT3+BIT4;
P2DIR|=BIT0+BIT1+BIT2+BIT3; //悬空的IO口要置为输出
//P1OUT =0; //不确定电平会造成IO耗电
P2OUT =0;
jinshu_Init();//金属检测初始化程序
BT_Init(64); //BasicTimer设为1/64秒中断一次
LCD_Init(); //LCD初始化
TACTL=TASSEL_1+MC_2+TAIE+TACLR;
UART_Init425();
//RTC_SetVal('h',12);
_EINT();
RTC_SetVal('m',0); //设置时间为12:30

unsigned int i;
while(1)
{ for(i=0;i<20;i++)
UART0_GetChar(Command149);
if(Command149[0]==0x08)
{ Dis_Shu[3]=Dis ;
_DINT();
for(i=0;i<2000;i++)
{
Hour=RTC_GetVal('h'); //获取"时"
Minute=RTC_GetVal('m'); //获取"分"
Second=RTC_GetVal('s'); //获取"秒"
LCD_DisplayChar(Minute/10,3);
LCD_DisplayChar(Minute%10,2); //显示"分"
LCD_DisplayChar(Second/10,1);
LCD_DisplayChar(Second%10,0); //显示"秒"
LCDM3|=0x10; //显
LCD_DisplayChar(3,5);
}
for(i=0;i<1000;i++)
{ LCD_DisplayDecimal(Dis_Shu[3],2);
}
for(i=0;i<1000;i++)
{LCD_DisplayDecimal(Dis_Shu[0],2);
LCD_DisplayChar(1,5);
}
for(i=0;i<1000;i++)
{LCD_DisplayDecimal(Dis_Shu[1],2);
LCD_DisplayChar(2,5);
}
for(i=0;i<1000;i++)
{LCD_DisplayDecimal(Dis_Shu[2],2);
LCD_DisplayChar(3,5);
}
LCD_Clear();
for(i=0;i<500;i++);
}

else
{

Hour=RTC_GetVal('h'); //获取"时"
Minute=RTC_GetVal('m'); //获取"分"
Second=RTC_GetVal('s'); //获取"秒"
LCD_DisplayChar(Minute/10,3);
LCD_DisplayChar(Minute%10,2); //显示"分"
LCD_DisplayChar(Second/10,1);
LCD_DisplayChar(Second%10,0); //显示"秒"
LCDM3|=0x10; //显示小数点

}

}
}
2、RTC.c
#include "msp430x42x.h"

unsigned char RTC_Time[7]={0,1,1,0,0,0};
#define YEAR RTC_Time[0]
#define MONTH RTC_Time[1]
#define DATE RTC_Time[2]
#define HOUR RTC_Time[3]
#define MINUTE RTC_Time[4]
#define SECOND RTC_Time[5]
int DSEC=0;
unsigned char const MONTH_Table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
unsigned char RTC_SR;
#define DISABLE_INT; RTC_SR=__get_SR_register();_DINT(); /*关闭中断的宏定义*/
#define RESTORE_INT; if(RTC_SR & GIE) _EINT(); /*恢复中断的宏定义*/
/****************************************************************************
* 名 称:RTC_Tick()
* 功 能:对实时钟进行走时和刷新
* 入口参数:Div_Sec: 定时器每秒中断的次数
* 出口参数:无
* 说 明: 该函数需要被周期性调用。最好放在定时中断内执行。建议使用
BasicTimer定时器产生所需的定时中断。
* 范 例: 在1/16秒中断内调用 RTC_Tick(16);
在5ms定时中断内调用 RTC_Tick(200);
****************************************************************************/
void RTC_Tick(int DivSec)
{ char Days;
DSEC++;
DISABLE_INT; //关闭中断以免运算到一半时被中断内其他函数读取。
if(DSEC >=DivSec) {SECOND++;DSEC=0;} //1秒一次
if(SECOND>=60) {MINUTE++;SECOND=0;} //60秒一次
if(MINUTE>=60) {HOUR++;MINUTE=0;} //60分一次
if(HOUR >=24) {DATE++;HOUR=0;} //24小时一次
if(MONTH==2) //处理润年2月份问题
{
if(YEAR%4==0) Days=29; //逢4年润二月
else Days=28;
}
else Days=MONTH_Table[MONTH-1]; //正常月份,查表得到当月天数
if(DATE >Days) {MONTH++;DATE=1;} //一个月一次
if(MONTH >12) {YEAR++;MONTH=1;} //一年一次
if(YEAR>=100) {YEAR=0;} //100年一次
RESTORE_INT;//恢复中断
}
/****************************************************************************
* 名 称:RTC_SetVal()
* 功 能:对实时钟某个参数进行设置
* 入口参数:Index: 设置内容 'Y'=年 'M'=月 'Y'=日 'h'=时 'm'=分 's'=秒
Value: 设置值. 年(0~99) 月(1~12) 日(1~31) 时(0~23) 分秒(0~59)
* 出口参数:返回1表示设置成功 返回0表示参数错误,设置失败
* 范 例: RTC_Set('h',13); //将"时"设为13
RTC_Set('m',35); //将"分"设为35
****************************************************************************/
char RTC_SetVal(unsigned char Index,unsigned char Value)
{
switch(Index) //根据当前设置内容选择程序分支
{
case 'Y': if(Value>99) return(0); //设置"年"
YEAR=Value; break;
case 'M': if(Value>12) return(0); //设置"月"
if(Value<1 ) return(0);
MONTH=Value; break;
case 'D': if(Value>31) return(0); //设置"日"
if(Value<1 ) return(0);
DATE=Value; break;
case 'h': if(Value>23) return(0); //设置"时"
HOUR=Value; break;
case 'm': if(Value>59) return(0); //设置"分"
MINUTE=Value; break;
case 's': if(Value>59) return(0); //设置"秒"
SECOND=Value; break;
default: return(0);
}
return(1);
}
/****************************************************************************
* 名 称:RTC_SetAll()
* 功 能:对实时钟全部参数进行设置
* 入口参数:Ptr : 数组[年月日时分秒]
* 出口参数:返回1表示设置成功 返回0表示参数错误,设置失败
* 范 例: RTC_SetAll(RTC_TimeArray);
RTC_TimeArray是一个unsigned char 型数组,RTC_TimeArrar[0]到RTC_TimeArrar[5]
依次存放着年、月、日、时、分、秒 数据
****************************************************************************/
char RTC_SetAll(unsigned char* Ptr)
{
char i;
if(Ptr[0]>99) return(0);
if(Ptr[1]>12) return(0);
if(Ptr[1]<1 ) return(0);
if(Ptr[2]>31) return(0);
if(Ptr[2]<1 ) return(0);
if(Ptr[3]>23) return(0); //排除错误参数
if(Ptr[4]>59) return(0);
if(Ptr[5]>59) return(0);
for(i=0;i<6;i++) RTC_Time[i]=Ptr[i]; //全部复制
return(1); //参数正确,返回1
}
/****************************************************************************
* 名 称:RTC_GetVal()
* 功 能:读取实时钟的某个参数
* 入口参数:Index: 读取内容 'Y'=年 'M'=月 'Y'=日 'h'=时 'm'=分 's'=秒
* 出口参数:读取结果。
* 范 例: Hour=RTC_Get('h'); //读取当前"时"
Minute=RTC_Set('m'); //读取当前"分"
****************************************************************************/
char RTC_GetVal(char Index)
{ char Value;
switch(Index) //根据当前读取内容选择程序分支
{
case 'Y': Value=YEAR; break; //读取"年"
case 'M': Value=MONTH; break; //读取"月"
case 'D': Value=DATE; break; //读取"日"
case 'h': Value=HOUR; break; //读取"时"
case 'm': Value=MINUTE; break; //读取"分"
case 's': Value=SECOND; break; //读取"秒"
default: return(255); //读取参数错误,返回255(-1)
}
return(Value);
}
/****************************************************************************
* 名 称:RTC_GetAll()
* 功 能:读取实时钟全部参数
* 入口参数:Ptr : 数组
* 出口参数:无
* 说 明: 读取结果按照年月日时分秒顺序存放在传入的数组中。
* 范 例: RTC_GetAll(RTC_TimeArray);
RTC_TimeArray是一个unsigned char 型数组,执行后,RTC_TimeArrar[0]到
RTC_TimeArrar[5] 依次存放读取的 年、月、日、时、分、秒 数据
****************************************************************************/
void RTC_GetAll(char* Ptr)
{
char i;
for(i=0;i<6;i++) Ptr[i]=RTC_Time[i]; //全部读取
}
3、BasicTimer.c
#include "msp430x42x.h" /*单片机寄存器头文件*/
#include "RTC.h" /*实时钟头文件*/
char BT_Flag=0;
/****************************************************************************
* 名 称:BT_Init()
* 功 能:对BasicTimer进行初始化设置
* 入口参数:Div_Sec: 定时器每秒产生中断次数。
* 出口参数:无
* 说 明: 如需使用后面的函数,在主循环之前必须先调用该初始化函数
****************************************************************************/
char BT_Init(int Div_Sec)
{
switch(Div_Sec)
{
case 20: BTCTL = BTDIV+BT_fCLK2_DIV256;break; // 2s BT Int
case 1: BTCTL = BTDIV+BT_fCLK2_DIV128;break; // 1s BT Int
case 2: BTCTL = BTDIV+BT_fCLK2_DIV64;break; // 1/2s BT Int
case 4: BTCTL = BTDIV+BT_fCLK2_DIV32;break; // 1/4s BT Int
case 8: BTCTL = BTDIV+BT_fCLK2_DIV16;break; // 1/8s BT Int
case 16: BTCTL = BTDIV+BT_fCLK2_DIV8;break; // 1/16s BT Int
case 32: BTCTL = BTDIV+BT_fCLK2_DIV4;break; // 1/32s BT Int
case 64: BTCTL = BTDIV+BT_fCLK2_DIV2;break; // 1/64s BT Int
case 128:BTCTL = BT_fCLK2_DIV256;break; // 1/128s BT Int
case 256:BTCTL = BT_fCLK2_DIV128;break; // 1/256s BT Int
case 512:BTCTL = BT_fCLK2_DIV64;break; // 1/512s BT Int
case 1024:BTCTL = BT_fCLK2_DIV32;break; // 1/1024s BT Int
case 2048:BTCTL = BT_fCLK2_DIV16;break; // 1/2048s BT Int
case 4096:BTCTL = BT_fCLK2_DIV8;break; // 1/4096s BT Int
case 8192:BTCTL = BT_fCLK2_DIV4;break; // 1/8192s BT Int
case 16384:BTCTL =BT_fCLK2_DIV2;break; // 1/16384s BT Int
default : return(0);
}
IE2 |= BTIE; // Enable Basic Timer interrupt
_EINT();
return(1);
}
/****************************************************************************
* 名 称:Cpu_SleepDelay()
* 功 能:靠CPU休眠实现延迟。
* 入口参数:BT_Time: BasicTimer中断次数
* 出口参数:无
* 说 明: 需要设置BasicTimer定时器,并开启中断。该延迟函数极省电
****************************************************************************/
void Cpu_SleepDelay(int BT_Time)
{
for(;BT_Time>0;BT_Time--)
{
BT_Flag=0;
while(BT_Flag==0) ;//LPM3; //只有BT中断才能唤醒CPU
BT_Flag=0;
}
}
/****************************************************************************
* 名 称:Cpu_SleepWaitBT()
* 功 能:CPU休眠,等待BT中断唤醒。
* 入口参数:无
* 出口参数:无
* 说 明: 需要设置BasicTimer定时器,并开启中断。该函数极省电
****************************************************************************/
void Cpu_SleepWaitBT()
{
BT_Flag=0;
while(BT_Flag==0) ;//LPM3; //只有BT中断才能唤醒CPU
BT_Flag=0;
}
/****************************************************************************
* 名 称:BT_ISR()
* 功 能:定时唤醒CPU。
* 入口参数:无
* 出口参数:无
****************************************************************************/
#pragma vector = BASICTIMER_VECTOR
__interrupt void BT_ISR(void) // 1/Div_Sec 秒一次中断(由BasicTimer所产生)
{
BT_Flag=1;
/*
在这里写中断服务程序,如扫描键盘、实时钟走时等。
*/
RTC_Tick(64); //RTC走时函数
//__low_power_mode_off_on_exit(); //唤醒CPU
}


使用特权

评论回复
5
hbzjt2011|  楼主 | 2015-6-11 11:05 | 只看该作者
4、LCD_Display.c
#include "msp430x42x.h"

/*宏定义,数码管a-g各段对应的比特,更换硬件只用改动以下8行*/
#define d 0x01 // AAAA
#define g 0x02 // F B
#define b 0x04 // F B
#define a 0x08 // GGGG
#define DOTSEG 0x10 // E C
#define e 0x20 // E C
#define f 0x40 // DDDD
#define c 0x80
#define NEGSEG 0x02
/*用宏定义自动生成段码表,很好的写法,值得学习*/
/*更换硬件无需重写段码表*/
const char LCD_Tab[] = {
a + b + c + d + e + f, // Displays "0"
b + c, // Displays "1"
a + b + d + e + g, // Displays "2"
a + b + c + d + g, // Displays "3"
b + c + f + g, // Displays "4"
a + c + d + f +g, // Displays "5"
a + c + d + e + f + g, // Displays "6"
a + b + c, // Displays "7"
a + b + c + d + e + f + g, // Displays "8"
a + b + c + d + f + g, // Displays "9"
a + b + c + e + f + g, // Displays "A"
c + d + e + f + g, // Displays "B"
a + d + e + f,         // Displays "C"
b + c + d + e + g, // Displays "D"
a + d + e + f + g, // Displays "E"
a + e + f + g,         // Displays "F"
a + c + d + e + f, // Displays "G"
b + c + e + f + g, // Displays "H"
e + f, // Displays "I"
b + c + d + e, // Displays "J"
b + d + e + f + g, // Displays "K"
d + e + f, // Displays "L"
a + c + e + g, // Displays "M"
a + b + c + e + f, // Displays "N"
c + e + g, // Displays "n"
c + d + e + g, // Displays "o"
a + b + c + d + e + f, // Displays "O"
a + b + e + f + g, // Displays "P"
a + b + c + f + g, // Displays "Q"
e + g,         // Displays "r"
a + c + d + f +g, // Displays "S"
d + e + f + g, // Displays "t"
a + e + f , // Displays "T"
b + c + d + e + f, // Displays "U"
c + d + e, // Displays "v"
b + d + f + g, // Displays "W"
b + c + d + f + g, // Displays "Y"
a + b + d + e + g, // Displays "Z"
g, // Displays "-"
b, // Displays "'"
0         // Displays " "
};
#undef a
#undef b
#undef c
#undef d
#undef e
#undef f
#undef g

#define AA 10
#define BB AA+1
#define CC BB+1
#define DD CC+1
#define EE DD+1
#define FF EE+1
#define GG FF+1
#define HH GG+1
#define II HH+1
#define JJ II+1
#define KK JJ+1
#define LL KK+1
#define mm LL+1
#define NN mm+1
#define nn NN+1
#define oo nn+1
#define OO oo+1
#define PP OO+1
#define QQ PP+1
#define rr QQ+1
#define SS rr+1
#define tt SS+1
#define TT tt+1
#define UU TT+1
#define VV UU+1
#define WW VV+1
#define YY WW+1
#define ZZ YY+1
#define BR ZZ+1 /* - */
#define DT BR+1 /* ' */
#define SP DT+1 /* 空白 */

/****************************************************************************
* 名 称:LCD_Init()
* 功 能:初始化LCD显示屏。
* 入口参数:无
* 出口参数:无
* 说 明: 在主程序LCD操作之前,需要调用该函数设置LCD参数。
****************************************************************************/
void LCD_Init()
{ char i;
char *pLCD = (char *)&LCDM1; // 取LCDM1寄存器(最低位)的地址
for (i = 0; i < 8; i++) // Clear LCD memory
*pLCD++ = 0; // 清屏
LCDCTL = LCDSG0_1 + LCD4MUX + LCDON; // LCD模式:4mux LCD, segs0-15
BTCTL |= BT_fLCD_DIV128; // 设置 LCD 刷新率
/*刷新率越慢功耗越低,但速度太慢LCD会闪烁*/
}

/****************************************************************************
* 名 称:LCD_DisplayLongDecimal()
* 功 能:在LCD上显示一个带有小数点的长数据。
* 入口参数:Number:显示数值 (-999999~9999999)
DOT :小数点位数(0~3)
* 出口参数:无
* 范 例: LCD_DisplayDecimal( 123456,2); 显示结果: 1234.56 (2位小数)
LCD_DisplayDecimal(-123456,1); 显示结果:-12345.6 (1位小数)
* 说 明: 该函数能够显示满屏7位数字,但执行时间较长,耗电大。
****************************************************************************/
void LCD_DisplayLongDecimal( long int Number, char DOT)
{
char Neg;
char i;unsigned char temp;
char *pLCD = (char *)&LCDM1;
char PolarLocate;
char DispBuff[8];

if(Number<0) {Number=-Number; Neg=1;} //处理负数
else Neg=0;
for(i=0;i<7;i++) //拆分数字
{
DispBuff[i]=Number%10;
Number/=10;
}
for(i=6;i>DOT;i--) //消隐无效"0"
{
if (DispBuff[i]==0) DispBuff[i]=SP;
else break;
}
PolarLocate=i+1; // 负号显示在第一个有效数字左边
if(DOT>3) DOT=255; // 无效的小数点不显示
if(DOT<1) DOT=255; // LCD048段码中只有123位数字有小数点
for(i=0;i<7;i++)
{
temp=LCD_Tab[DispBuff[i]]; //查表
if (DOT==i) temp|=DOTSEG;//显示小数点
if ((PolarLocate==i)&&(Neg)) temp|=NEGSEG;//负号
pLCD[i]=temp; //写入显存
}
}
/****************************************************************************
* 名 称:LCD_DisplayDecimal()
* 功 能:在LCD上显示一个带有小数点的短整型数据。
* 入口参数:Number:显示数值 (-32768~32767)
DOT :小数点位数(0~3)
* 出口参数:无
* 范 例: LCD_DisplayDecimal( 12345,2); 显示结果: 123.45 (2位小数)
LCD_DisplayDecimal(-12345,1); 显示结果:-1234.5 (1位小数)
* 说 明: 该函数显示数值范围小,但执行时间短,耗电小。
****************************************************************************/
void LCD_DisplayDecimal( int Number, char DOT)
{
char Neg;
char i;unsigned char temp;
char *pLCD = (char *)&LCDM1;
char PolarLocate;
char DispBuff[8];

if(Number<0) {Number=-Number; Neg=1;} //处理负数
else Neg=0;
for(i=0;i<7;i++) //拆分数字
{
DispBuff[i]=Number%10;
Number/=10;
}
for(i=6;i>DOT;i--) //消隐无效"0"
{
if (DispBuff[i]==0) DispBuff[i]=SP;
else break;
}
PolarLocate=i+1; // 负号显示在第一个有效数字左边
if(DOT>3) DOT=255; // 无效的小数点不显示
if(DOT<1) DOT=255; // LCD048段码中只有123位数字有小数点
for(i=0;i<7;i++)
{
temp=LCD_Tab[DispBuff[i]]; //查表
if (DOT==i) temp|=DOTSEG;//显示小数点
if ((PolarLocate==i)&&(Neg)) temp|=NEGSEG;//负号
pLCD[i]=temp; //写入显存
}
}

/****************************************************************************
* 名 称:LCD_DisplayLongNumber()
* 功 能:在LCD上显示一个长整数。
* 入口参数:Number:显示数值 (-999999~9999999)
* 出口参数:无
* 范 例: LCD_DisplayNumber( 123456); 显示结果: 123456
LCD_DisplayNumber(-123456); 显示结果:-123456
* 说 明: 该函数能够显示满屏7位数字,但执行时间较长,耗电大。
****************************************************************************/
void LCD_DisplayLongNumber(long int Number)
{
LCD_DisplayLongDecimal(Number,0) ;//整数没有小数点
}
/****************************************************************************
* 名 称:LCD_DisplayNumber()
* 功 能:在LCD上显示一个短整数。
* 入口参数:Number:显示数值 (-32768~32767)
* 出口参数:无
* 范 例: LCD_DisplayNumber( 12345); 显示结果: 12345
LCD_DisplayNumber(-12345); 显示结果:-12345
****************************************************************************/
void LCD_DisplayNumber(int Number)
{
LCD_DisplayDecimal(Number,0) ;//整数没有小数点
}
/****************************************************************************
* 名 称:LCD_DisplayChar()
* 功 能:在LCD上显示一个字符。
* 入口参数:ch :显示内容 可显示字母请参考LCD_Display.h中的宏定义
Location:显示位置 从左至右对应76543210
* 出口参数:无
* 说 明: 调用该函数不影响LCD其他位的显示。但显示数字的函数会覆盖该函数的结
果,因此该函数要在显示数据函数之后调用。
* 范 例: LCD_DisplayChar(AA,4);
LCD_DisplayChar(PP,5);
LCD_DisplayChar(2 ,6); 显示结果: 2PAXXXX
****************************************************************************/
void LCD_DisplayChar(char ch,char Location)
{
char *pLCD = (char *)&LCDM1;
pLCD[Location]=LCD_Tab[ch];
}
/****************************************************************************
* 名 称:LCD_InsertChar()
* 功 能:在LCD最右端插入一个字符。
* 入口参数:ch :插入字符 可显示字母请参考LCD_Display.h中的宏定义
* 出口参数:无
* 说 明: 调用该函数后,LCD所有已显示字符左移一位,新的字符插入在最右端一位。
该函数可以实现滚屏动画效果,或用于在数据后面显示单位。
* 范 例: LCD_DisplayDecimal(1234,1);
LCD_InsertChar(PP);
LCD_InsertChar(FF);显示结果: 123.4PF

****************************************************************************/
void LCD_InsertChar(char ch)
{ char i;
char *pLCD = (char *)&LCDM1;
for(i=6;i>=1;i--) pLCD[i]=pLCD[i-1];
pLCD[0]=LCD_Tab[ch];
}
/****************************************************************************
* 名 称:LCD_ON()
* 功 能:开启LCD显示
* 入口参数:无
* 出口参数:无
* 说 明: 调用该函数将开启LCD显示。开启后LCD仍显示最后一次显示内容
****************************************************************************/
void LCD_ON()
{
LCDCTL |= LCDON;
}
/****************************************************************************
* 名 称:LCD_ON()
* 功 能:关闭LCD显示
* 入口参数:无
* 出口参数:无
* 说 明: 调用该函数将关闭LCD显示,可节省3~5uA电流。该函数不清除显示内容。
****************************************************************************/
void LCD_OFF()
{
LCDCTL &=~ LCDON;
}

/****************************************************************************
* 名 称:LCD_Clear()
* 功 能: 清除LCD显示
* 入口参数:无
* 出口参数:无
* 说 明: 调用该函数将LCD显示清除,但并不关闭LCD模块。
****************************************************************************/
void LCD_Clear()
{ char i;
char *pLCD = (char *)&LCDM1; // 取LCDM1寄存器(最低位)的地址
for (i = 0; i < 8; i++) // Clear LCD memory
{
*pLCD++ = 0; //清屏
}
}
5、Key.c
#include "MSP430x42x.h"
#define KEYBUFF_SIZE 8 /*键盘缓冲区大小,根据程序需要自行调整*/
char KeyBuff[KEYBUFF_SIZE]; //定义键盘缓冲队列数组(FIFO)
char Key_IndexW=0; //键盘缓冲队列写入指针(头指针)
char Key_IndexR=0; //键盘缓冲队列读取指针(尾指针
char Key_Count=0; //键盘缓冲队列内记录的按键次数

char P_KEY1=255; //存放KEY1前一次状态的变量
char N_KEY1=255; //存放KEY1当前状态的变量
char P_KEY2=255; //存放KEY2前一次状态的变量
char N_KEY2=255; //存放KEY2当前状态的变量
char P_KEY3=255; //存放KEY3前一次状态的变量
char N_KEY3=255; //存放KEY3当前状态的变量



#define KEY1_IN (P1IN&BIT5) //KEY1输入IO的定义(P1.5)
#define KEY2_IN (P1IN&BIT6) //KEY2输入IO的定义(P1.6)
#define KEY3_IN (P1IN&BIT7) //KEY3输入IO的定义(P1.7)

#define PUSH_KEY1 0x01
#define PUSH_KEY2 0x02 /*键值宏定义*/
#define PUSH_KEY3 0x04

unsigned char KEY_SR;
#define DISABLE_INT; KEY_SR=__get_SR_register();_DINT();
#define RESTORE_INT; if(KEY_SR & GIE) _EINT();
/****************************************************************************
* 名 称:Key_Init()
* 功 能:初始化键盘所在的IO口
* 入口参数:无
* 出口参数:无
****************************************************************************/
void Key_Init()
{
P1DIR&=~(BIT5+BIT6+BIT7); //P1.5/6/7作为输入
}
/****************************************************************************
* 名 称:Key_InBuff()
* 功 能:将一次键值压入键盘缓冲队列
* 入口参数:Key:被压入缓冲队列的键值
* 出口参数:无
****************************************************************************/
void Key_InBuff(char Key)
{
if(Key_Count>=KEYBUFF_SIZE) return;//若缓冲区已满,放弃本次按键
DISABLE_INT;
Key_Count++; //按键次数计数增加
KeyBuff[Key_IndexW] = Key; //从队列头部追加新的数据
if (++Key_IndexW >= KEYBUFF_SIZE) //循环队列,如果队列头指针越界
{
Key_IndexW = 0; //队列头指针回到数组起始位置
}
RESTORE_INT;
}
/****************************************************************************
* 名 称:Key_GetKey()
* 功 能:从键盘缓冲队列内读取一次键值
* 入口参数:无
* 出口参数:若无按键,返回0,否则返回一次按键键值。
* 说 明: 调用一次该函数,会自动删除缓冲队列里一次按键键值。
****************************************************************************/
char Key_GetKey()
{ char Key;
if(Key_Count==0) return(0); //若无按键,返回0
DISABLE_INT;//队列操作过程中不允许被定时中断执行ScanIO函数,保护全局变量正确
Key_Count--; //按键次数计数减1
Key=KeyBuff[Key_IndexR]; //从缓冲区尾部读取一个按键值
if (++Key_IndexR >= KEYBUFF_SIZE)//循环队列,如果队列尾指针越界
{
Key_IndexR = 0; //队列尾指针回到数组起始位置
}
RESTORE_INT; //恢复中断允许
return(Key);
}
/****************************************************************************
* 名 称:Key_WaitKey()
* 功 能:从键盘缓冲队列内读取一次键值
* 入口参数:无
* 出口参数:若有按键,返回键值,否则等待按键。
* 说 明: 该函数会阻塞CPU继续执行后面的程序,应用时需注意。
****************************************************************************/
char Key_WaitKey()
{ char Key;
while(1)
{
Key=Key_GetKey(); //从键盘缓冲队列读取一次键值
if(Key==0) LPM3; //如果没按键,则停止CPU,等待被唤醒继续读按键
else return(Key); //如果有按键,则返回键值
}
}

/****************************************************************************
* 名 称:Key_ScanIO()
* 功 能:扫描键盘IO口并判断按键事件
* 入口参数:无
* 出口参数:无,键值压入缓冲队列
* 说 明: 该函数需要每隔1/16秒至1/128秒调用一次。最好放在定时中断内执行。
如果中断间隔太长,可能丢键;间隔太短不能消除抖动。
****************************************************************************/
void Key_ScanIO()
{
P_KEY1=N_KEY1; //保存KEY1前一次的状态
N_KEY1=KEY1_IN; //读取KEY1当前的状态

P_KEY2=N_KEY2; //保存KEY2前一次的状态
N_KEY2=KEY2_IN; //读取KEY2当前的状态

P_KEY3=N_KEY3; //保存KEY3前一次的状态
N_KEY3=KEY3_IN; //读取KEY3当前的状态

if((P_KEY1!=0)&&(N_KEY1==0)) Key_InBuff(PUSH_KEY1);
if((P_KEY2!=0)&&(N_KEY2==0)) Key_InBuff(PUSH_KEY2);
if((P_KEY3!=0)&&(N_KEY3==0)) Key_InBuff(PUSH_KEY3);

}
6、jinshu.c
#include "msp430x42x.h"
#include "Uart.h"
#include "LCD_Display.h"
#include "RTC.h"

#define Circle 46
char Jinshu_Shu;//定义检测到金属的片数
unsigned int TA_Overflowcnt;
unsigned long int period;
unsigned int Dis;
unsigned int cnt;
extern char Second;
unsigned int Dis_Shu[4];
void jinshu_Init(void) //金属检测初始化程序
{
Jinshu_Shu=0; //初始化 检测到金属的片数为零

// 初始化 测速 金属检测初始化程序
P1DIR&=~(BIT3+BIT5); //把P1^2,P1.5初始化为输入
P1IES|=BIT3+BIT5; //把其定义为初始化下降沿触发中断
P1IE|=BIT3+BIT5; //p1.3,P1.5中断允许
TACTL=TASSEL_1+MC_2+TAIE+TACLR;
BTCTL=0;
}

#pragma vector =PORT1_VECTOR
__interrupt void PORT1_ISR(void) //p1口中断服务程序
{
unsigned int i;
unsigned int j;
for(i=2000;i>0;i--);//延时进行消除抖动
if (P1IFG & BIT3)
{
//表示小车可能将要进铁片入区域
if((P1IN&BIT3)==0) //表示小车刚进入铁片区域
{ Dis_Shu[Jinshu_Shu]= Dis ;
Jinshu_Shu++; //铁片数目加1
LCD_DisplayChar(Jinshu_Shu,5);

P1IFG=0;
if(Jinshu_Shu==3)
{for(i=0;i<5;i++)
UART0_PutChar(0x02); //停车
}
else
{for(i=0;i<5;i++)
UART0_PutChar(0x01);
}
//LCD_DisplayDecimal(Dis,2);

//可以在这里调用串口通信程序,向MSP149发送信息,打开声光指示程序
}
}
// 与测速有关的部分
_BIC_SR(SCG0);
if((P1IN&BIT5)==BIT5)
{
P1IFG=0;
//return;
}
if (P1IFG & BIT5);
for(j=0;j<2000;j++)
if (P1IFG & BIT5);
{
cnt++;
Dis = cnt * Circle;
//LCD_DisplayDecimal(Dis,1);

}
P1IFG=0;

}

#pragma vector=TIMERA1_VECTOR
__interrupt void TA_ISR(void)
{
switch(TAIV)
{
case 2:break;
case 4:break;
case 10:TA_Overflowcnt++;
break;
}
}
7、UART.c
#include <msp430x14x.h>
#define RXBUF_SIZE 32
#define TXBUF_SIZE 32 //发送FIFO的最大容量

unsigned char RX_BUFF[RXBUF_SIZE];
unsigned int UART_InpLen = 0;
unsigned int RX_IndexR = 0;
unsigned int RX_IndexW = 0;
unsigned char TX_BUFF[TXBUF_SIZE]; //发送FIFO缓冲区数据
unsigned int UART_OutLen=0; //发送FIFO内等待发出的字节数
unsigned int TX_IndexR=0; //发送FIFO的读指针
unsigned int TX_IndexW=0; //发送FIFO的写指针
unsigned char Command[5];

//149串口初始化
UART_Init149()
{
U0CTL |= CHAR; //异步通讯模式,8位数据,无校验,1位停止位
ME1 |= UTXE0 + URXE0; //开启串口0收发模块
U0TCTL |= SSEL0; //选择ACLK作为串口波特率时钟源
U0BR1 = 0; //
U0BR0 = 13; //分频系数整数部分=13
U0MCTL = 0X6B; //分频系数小数部分调制=5/8.(2400bps)
P3SEL |= BIT4 + BIT5;
U0CTL &=~ SWRST; //启动串口
IE1 |= URXIE0;
}

UART_Init425()
{
U0CTL |= CHAR; //异步通讯模式,8位数据,无校验,1位停止位
ME1 |= UTXE0 + URXE0; //开启串口0收发模块
U0TCTL |= SSEL0; //选择ACLK作为串口波特率时钟源
U0BR1 = 0; //
U0BR0 = 13; //分频系数整数部分=13
U0MCTL = 0X6B; //分频系数小数部分调制=5/8.(2400bps)
P2SEL |= BIT4 + BIT5; //
U0CTL &=~ SWRST; //启动串口
IE1 |= URXIE0;
}

/*********************************************************
名称: UART0_GetChar()
功能: 从串口读一个字节数据
入口参数: 数据存放的地址指针
出口参数: 0表示失败,1表示成功
说明: 读取过程不阻塞CPU运行
*********************************************************/

char UART0_GetChar(unsigned char *Chr)
{
if(UART_InpLen == 0) return (0);
_DINT();
UART_InpLen--;
*Chr = RX_BUFF[RX_IndexR];
if (++RX_IndexR >= RXBUF_SIZE)
{ RX_IndexR = 0;
}
_EINT();
return (1);
}

/*********************************************************
名称: UART0_GetCharsInRxBuf()
功能:
入口参数:
出口参数: 待读取的字节数
*********************************************************/
unsigned int UART0_GetCharsInRxBuf()
{
return (UART_InpLen);
}
/*********************************************************
名称: UART0_ClrRxBuf()
功能: 清除接收队列
入口参数:
出口参数:
*********************************************************/

void UART0_ClrRxBuf()
{
_DINT();
UART_InpLen = 0;
RX_IndexR = 0;
RX_IndexW = 0;
_EINT();
}

//串口接收中断
#pragma vector= UART0RX_VECTOR
__interrupt void UART0_RX (void)
{
UART_InpLen ++;
RX_BUFF[RX_IndexW] =U0RXBUF;
if (++RX_IndexW >= RXBUF_SIZE)
{
RX_IndexW = 0;
}
}

/********************************************************************
名称:char UART0_PutChar()
功能:向串口发送一字节
入口参数: Chr,待发字节
出口参数: 返回1成功,0失败
********************************************************************/
char UART0_PutChar(unsigned char Chr)
{
if(UART_OutLen == TXBUF_SIZE)
{
return(0);
}
if(UART_OutLen == 0)
{
IFG1 |= UTXIFG0;
}
_DINT();
UART_OutLen++;
TX_BUFF[TX_IndexW] = Chr;
if (++TX_IndexW >= TXBUF_SIZE)
{
TX_IndexW = 0;
}
IE1 |= UTXIE0;
_EINT();
return (1);
}


//串口发送中断
#pragma vector=UART0TX_VECTOR
__interrupt void UART0_TX (void)
{
if(UART_OutLen>0)
{
UART_OutLen--;
U0TXBUF = TX_BUFF[TX_IndexR];
if(++TX_IndexR >= TXBUF_SIZE)
{
TX_IndexR = 0;
}
}
else IE1 &=~ UTXIE0;
}


使用特权

评论回复
6
FireRiver9| | 2015-6-11 21:05 | 只看该作者
楼主大神,mark

使用特权

评论回复
7
hbzjt2011|  楼主 | 2015-6-11 21:41 | 只看该作者

共同学习,共同进步!

使用特权

评论回复
8
冰河w| | 2015-6-12 20:30 | 只看该作者
好资料,必须mark

使用特权

评论回复
9
comeon201208| | 2015-6-13 20:30 | 只看该作者
以MSP超低功耗单片机系列MSP430F149和MSP430FE425为核心,完成小车的寻迹、检测金属、避障、寻光、测速等功能。

使用特权

评论回复
10
comeon201208| | 2015-6-13 20:31 | 只看该作者
在机械结构上,对普通的小车作了改进,即用一个万用轮来代替两个前轮,使小车的转向更加灵敏。采用PWM 驱动芯片控制电机,红外传感器检测黑线,金属传感器检测铁片,光敏器件检测光强,红外 LED 和一体化接收头来避障。

使用特权

评论回复
11
lwsn| | 2015-6-25 21:25 | 只看该作者
楼主的检测金属模块是怎么做的

使用特权

评论回复
12
yf201306| | 2016-4-10 16:46 | 只看该作者
楼主能不能将原理图发给我,详细一点的(主要是付的图片不清晰),还有就是那两个单片机怎么通信,邮箱:1913874509@qq.com

使用特权

评论回复
13
蔬木果| | 2018-7-7 00:13 | 只看该作者
学习了,mark。

使用特权

评论回复
14
pmp| | 2018-7-13 13:41 | 只看该作者
以为是平衡车的设计呢。

使用特权

评论回复
15
vivilzb1985| | 2018-7-16 10:11 | 只看该作者
以MSP超低功耗单片机系列MSP430F149和MSP430FE425为核心,完成寻迹、检测金属、避障、寻光、测速等功能。

使用特权

评论回复
16
shenmu2012| | 2018-7-16 22:03 | 只看该作者
采用PWM 驱动芯片控制电机,红外传感器检测黑线,金属传感器检测铁片,光敏器件检测光强,红外 LED 和一体化接收头来避障。

使用特权

评论回复
17
shenmu2012| | 2018-7-16 22:03 | 只看该作者
对电机的控制还是采用PWM的信号的哈

使用特权

评论回复
18
quickman| | 2018-7-16 22:08 | 只看该作者

使用特权

评论回复
19
jstgotodo| | 2018-7-16 22:08 | 只看该作者
做个平衡车吧。

使用特权

评论回复
20
iamaiqiyi| | 2018-7-16 22:08 | 只看该作者
简易智能电动怎样

使用特权

评论回复
发新帖 本帖赏金 3.10元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:欢迎参与LabVIEW版块的讨论学习! 点我一键即达

157

主题

2338

帖子

41

粉丝