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

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

[复制链接]
5767|50
 楼主| hbzjt2011 发表于 2015-6-11 09:53 | 显示全部楼层 |阅读模式
本帖最后由 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:
           

实物照片:




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

打赏榜单

liuxing4585 打赏了 0.10 元 2015-07-01

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

 楼主| hbzjt2011 发表于 2015-6-11 11:01 | 显示全部楼层
源码程序:
          MSP430F149 程序:1、main.c
  1. #include <msp430x14x.h>
  2. #include "Sensor.h"
  3. #include "Clock.h"
  4. #include "dianji.h"
  5. #include "Avoid.h"
  6. #include "mean.h"
  7. #include "ADC12.h"
  8. #include "Uart.h"


  9. Start()
  10. { int i;
  11. for (i=0;i<=30000;i++);
  12. }

  13. void main(void)
  14. { WDTCTL = WDTPW + WDTHOLD;
  15. BCS_Init();
  16. TB_Init();
  17. TimerAInit();
  18. Init_PWM_Driver();
  19. ADC12_Init();
  20. InitSensor();
  21. Port_Init();
  22. UART_Init149();
  23. Start();
  24. _EINT();
  25. while(1)
  26. {
  27. if(Flag_Stop == 0x01)
  28. {
  29. UART0_PutChar(0x08); //结束了
  30. }
  31. }
  32. }
2、Sensor.c
  1. #include <MSP430X14X.h>
  2. #include "Clock.h"

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

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

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

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

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

  24. //6只传感器的输入

  25. #define P_coefficient 600
  26. #define I_coefficient 0
  27. #define D_coefficient 300
  28. #define High_v 1000
  29. #define Low_v 950
  30. #define No_black 5000//找不到黑线时的转弯量控制
  31. #define No_f_black 6000//前边找不到黑线时的转弯量控制

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

  36. signed char Go_On_Black();
  37. void Handle_No_Black();

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

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

  49. }


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

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

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

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

  82. PSEN36_H ;
  83. Delay(32);
  84. SensorData[2]=SEN3_IN;
  85. SensorData[5]=SEN6_IN;
  86. PSEN36_L ;

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

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

  127. //右电机由CCR2,CCR3控制,CCR2高时为正转
  128. //左电机右CCR4,CCR5控制,CCR4高时为正转
  129. /*设置小车转弯量*/
  130. void Set_Rotation (int Rotation)
  131. //用-1000~+1000表示左转满舵~右转满舵
  132. {
  133. //if(Rotation==No_black)
  134. //Handle_No_Black();
  135. //else
  136. if(Rotation>0) //Rotation大于0是右转,
  137. {
  138. TBCCR2=High_v; //右轮减速,
  139. TBCCR3=0;
  140. TBCCR4=High_v-Rotation; //左轮全速前进,
  141. TBCCR5=0;
  142. }
  143. else //Rotation小于0是左转
  144. {
  145. TBCCR4=High_v; //左轮减速(注意Rotation是负值,加运算就是减速)
  146. TBCCR5=0;
  147. TBCCR3=0;
  148. TBCCR2=High_v+Rotation; //左轮全速

  149. }

  150. }


  151. /*错误处理 */
  152. void Handle_No_Black()
  153. {
  154. signed int j;
  155. signed char L_l,L_r;
  156. L_l=Last_Position[0];
  157. L_r=Last_Position[9];
  158. Last_Position[0]=0;Last_Position[1]=0;Last_Position[2]=0;Last_Position[3]=0;Last_Position[4]=0;
  159. Last_Position[5]=0;Last_Position[6]=0;Last_Position[7]=0;Last_Position[8]=0;Last_Position[9]=0;
  160. if(L_l<=L_r)
  161. {
  162. TBCCR4=High_v-30; //右轮全速前进
  163. TBCCR5=0;
  164. for(;R_up<=High_v;)
  165. {
  166. if(R_up<0)
  167. {
  168. TBCCR2=0;
  169. TBCCR3=-R_up; //左轮减速
  170. R_up+=(2*R_add);
  171. }
  172. else
  173. {
  174. TBCCR2=R_up;
  175. TBCCR3=0; //左轮减速
  176. R_up+=R_add;
  177. }
  178. if(R_up>High_v){R_up=-600;break;}
  179. for(j=0;j<(700+R_up)/2;j++)
  180. {
  181. if(Go_On_Black()==5)continue;
  182. else break;
  183. }
  184. if(Go_On_Black()==5)continue;
  185. else break;
  186. }
  187. }
  188. else
  189. {
  190. TBCCR2=High_v; //左轮全速前进
  191. TBCCR3=0;
  192. for(;R_up<=High_v;)
  193. {
  194. if(R_up<0)
  195. {
  196. TBCCR5=-R_up;
  197. TBCCR4=0; //右轮减速
  198. R_up+=(2*R_add);
  199. }
  200. else
  201. {
  202. TBCCR5=0;
  203. TBCCR4=R_up; //右轮减速
  204. R_up+=R_add;
  205. }
  206. if(R_up>High_v){R_up=-600;break;}
  207. //for(j=0;j<(700+R_up)/2;j++)
  208. //{
  209. // if(Go_On_Black()==5)continue;
  210. //else break;
  211. // }
  212. //if(Go_On_Black()==5)continue;
  213. else break;
  214. }
  215. }
  216. R_up=-600;
  217. }

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

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

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

  11. unsigned int Parking5s=0;
  12. unsigned char Flag_Parking=0;
  13. unsigned long int interrupt_time1=0x00;
  14. unsigned long int interrupt_time2=0x00;
  15. int Rotation;
  16. signed char Position;


  17. // XT2高频晶振2失效标志检查
  18. void XT2_Init(void)
  19. {
  20. unsigned char i;
  21. BCSCTL1 &= ~(XT2OFF);
  22. do{
  23. IFG1 &= ~(OFIFG);
  24. for(i=0; i<100; i++)
  25. {
  26. _NOP();
  27. }
  28. }
  29. while((IFG1 & OFIFG) != 0);
  30. }

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


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

  49. }

  50. void Delay(unsigned char Time) //延迟程序
  51. {
  52. unsigned int i,k;
  53. for(k=0;k<Time;k++)
  54. for(i=0;i<Time;i++);
  55. }




  56. // TBCCO 中断服务
  57. #pragma vector = TIMERB0_VECTOR
  58. __interrupt void TBCC0_IRQ(void)
  59. { // unsigned char i;
  60. if(Flag_Parking == 1)
  61. Parking5s++;
  62. UART0_GetChar(Command);
  63. if(Command[0]==0x01)
  64. {
  65. //Delay5s();
  66. P4DIR|=BIT1;
  67. P4OUT&=~BIT1;
  68. Delay(100);
  69. P4OUT|=BIT1;
  70. Command[0]=0;
  71. }
  72. if(Command[0]==0x02) //02为检测到第三块时的停车命令,然后149自己延时5s
  73. {
  74. TACCTL1&=~CCIE;
  75. TACCTL2&=~CCIE;
  76. Flag_Parking =1;
  77. P4DIR|=BIT0;
  78. P4OUT|=BIT0;
  79. P4OUT|=BIT1;
  80. P4OUT&=~BIT1;
  81. Delay(100);
  82. P4OUT|=BIT1;
  83. //延时五秒函数
  84. Stop();

  85. //TACCTL1&=~CCIE; //Unenable interrupt
  86. //TACCTL2&=~CCIE;

  87. Command[0]=0;
  88. //
  89. }
  90. if(Flag_Stop == 0x01)
  91. {
  92. TACCTL1&= ~CCIE; //Unenable interrupt
  93. TACCTL2&= ~CCIE;
  94. Stop();

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

  96. }
  97. if(Parking5s == 160)
  98. {TACCTL2|=CCIE;
  99. P4OUT&=~BIT0;
  100. P4OUT&=~BIT1;
  101. Delay(100);
  102. P4OUT|=BIT1;
  103. Flag_Parking = 0;
  104. Parking5s++;
  105. }
  106. }

  107. void TB_Init(void)
  108. {
  109. TBCTL = TBSSEL_1 + TBCLR + ID_0 + MC_0;
  110. TBCCR0 = 1024;
  111. TBCTL = TBSSEL_1 + TBCLR + ID_0 + MC_1;
  112. TBCCTL0 |= CCIE;

  113. }

  114. #pragma vector=TIMERA1_VECTOR //节拍控制
  115. __interrupt void Timer_A(void)
  116. {
  117. switch(TAIV)
  118. {
  119. case 2: interrupt_time1++;if(interrupt_time1==1000){Position=ReadSensor();// 检测黑线,计算位置
  120. Rotation=PID_Control(Position); // PID控制算法
  121. Set_Rotation(Rotation);//设置小车转弯量
  122. interrupt_time1=0x00;
  123. }
  124. break;
  125. case 4: interrupt_time2++;if(interrupt_time2==1000){ADC12_Deal();
  126. Measure_Light();
  127. Measure_Distance();
  128. FSM();
  129. //Find_Light();
  130. interrupt_time2=0x00;}
  131. break;
  132. default: break;
  133. }
  134. }


  135. void Interrupt_Stop()
  136. {
  137. TACCTL1&= ~CCIE; //Unenable interrupt
  138. TACCTL2&= ~CCIE;
  139. }

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

  25. /*转弯部分*/
  26. void Turn_Left() //左转函数
  27. {TBCCR2=0;
  28. TBCCR3=0;
  29. TBCCR4=1000;
  30. TBCCR5=0;
  31. }
  32. void Turn_Right()//右转函数
  33. {TBCCR2=1000;
  34. TBCCR3=0;
  35. TBCCR4=0;
  36. TBCCR5=0;

  37. }
  38. void Turn_Normal()//直行函数
  39. {TBCCR2=1000;
  40. TBCCR3=0;
  41. TBCCR4=1000;
  42. TBCCR5=0;
  43. }

  44. void Turn_Back()//直退函数
  45. {TBCCR2=0;
  46. TBCCR3=1000;
  47. TBCCR4=0;
  48. TBCCR5=1000;
  49. }

  50. void Stop()//停止函数
  51. {TBCCR5=0;
  52. TBCCR2=0;
  53. TBCCR3=0;
  54. TBCCR4=0;
  55. }

  56. void Test()//测试运行
  57. { int i = 0;
  58. Turn_Right();
  59. for(i=0;i<100;i++)
  60. Delay(100);

  61. Turn_Left();
  62. for(i=0;i<100;i++)
  63. Delay(100);

  64. //Turn_Back();

  65. }


 楼主| hbzjt2011 发表于 2015-6-11 11:01 | 显示全部楼层
5、Avoid.c

  1. #include <msp430x14x.h>
  2. #include "avoid.h"
  3. #include "dianji.h"
  4. #include "Clock.h"
  5. #include "mean.h"

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

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

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

  12. unsigned int cnt = 0;

  13. void Port_Init()
  14. {
  15. P2DIR |= BIT7 + BIT6 +BIT5 + BIT4+ BIT3;
  16. P2OUT |= BIT7 + BIT6 +BIT5 + BIT4+ BIT3;
  17. }


  18. /*测障碍物*/
  19. //BarrierData的值离障碍物越近,数值越大,5是距离最近的,为0说明没有检测到
  20. void Measure_Distance()
  21. {
  22. unsigned char flag_1=0,flag_2=0,flag_3=0,flag_4=0,flag_0=0;
  23. //unsigned char i,Frequency[5] = {29,36,44,47,51}; //66,54,44,42,38
  24. // 1
  25. if(flag_0==0)
  26. {
  27. Delay(34);
  28. PIRE1_H; // 打开1号传感器
  29. Delay(34); // 延迟,等待数据稳定
  30. if(IRE1_IN==0) // 如果接收到的信号为低电平,表明前方有障碍物
  31. {flag_0 = 1;BarrierData[0]=1;}
  32. else BarrierData[0]=0;
  33. PIRE1_L;
  34. }
  35. //2
  36. if(flag_1==0)
  37. {
  38. Delay(34);
  39. PIRE2_H; // 打开2号传感器
  40. Delay(34); // 延迟,等待数据稳定
  41. if(IRE1_IN==0) // 如果接收到的信号为低电平,表明前方有障碍物
  42. {flag_1 = 1;BarrierData[1]=1;}
  43. else BarrierData[1]=0;
  44. PIRE2_L;
  45. }
  46. // 3
  47. if(flag_2==0)
  48. {
  49. PIRE3_H ; // 打开3号传感器    
  50. Delay(34); // 延迟,等待数据稳定


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

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

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

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

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


  82. //

  83. void Avoid_Obstacle()//采用矢量合成,与寻光不同,避障的推力为负,所以坐标取反
  84. { if(flag == 1)
  85. {
  86. if((BarrierData[3]+BarrierData[4])>0) //
  87. {
  88. Turn_Left();
  89. }
  90. else if((BarrierData[0]+BarrierData[1])>0)//右边没有障碍
  91. {
  92. Turn_Right();
  93. }
  94. else
  95. {
  96. Turn_Left();
  97. }

  98. }
  99. else
  100. {
  101. Turn_Normal();
  102. }
  103. }

  104. void FSM()
  105. { //Find_Light();
  106. switch (Status)
  107. {case Light_Status : Find_Light(); break;
  108. case Barrier_Status : Avoid_Obstacle(); break;
  109. default: break;
  110. }

  111. }

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

  115. else
  116. {
  117. //1号红外,X轴正向,Y为0
  118. x=x+Barrier[0]*BarrierData[0];
  119. //2号,X为正,Y为负,45°
  120. x=x+707*Barrier[1]*BarrierData[1]/1000;
  121. y=y-707*Barrier[1]*BarrierData[1]/1000;
  122. //3号,X为0,Y为负
  123. y=y-Barrier[2]*BarrierData[2];
  124. //4号,X为负,Y为负,45°
  125. x=x-707*Barrier[3]*BarrierData[3]/1000;
  126. y=y-707*Barrier[3]*BarrierData[3]/1000;
  127. //5号,Y为0,X为负
  128. x=x-Barrier[4]*BarrierData[4];
  129. }
  130. if (flag_ahead==0) y=1000;
  131. }
  132. */

  133. /*带45°处理备份
  134. void Avoid_Obstacle()//采用矢量合成,与寻光不同,避障的推力为负,所以坐标取反
  135. { if(flag == 1)
  136. {
  137. if((BarrierData[0]==0)&&(BarrierData[1]==0))//左边没有障碍
  138. {
  139. Turn_Left();
  140. }
  141. else
  142. {
  143. if((BarrierData[4]==0)&&(BarrierData[3]==0))//右边没有障碍
  144. {
  145. Turn_Right();
  146. }
  147. else
  148. {
  149. Turn_Back();
  150. }
  151. }
  152. }
  153. else
  154. {
  155. Turn_Normal();
  156. }
  157. }
  158. */
6、mean.c
  1. #include <msp430x14x.h>
  2. #include "ADC12.h"
  3. #include "Clock.h"
  4. #include "dianji.h"
  5. #define Intensity 150 //光强权值


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

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

  44. }
  45. Minimum = Light[0];
  46. for(i=1;i<5;i++)
  47. { if(Minimum > Light[i])
  48. Minimum = Light[i];
  49. }
  50. for(i=0;i<5;i++)
  51. Light[i] = Light[i] - Minimum;

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

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

  61. y=y+Intensity * Light[2];
  62. //4号光敏电阻,X,Y都为+0.707,45度
  63. x=x+(Intensity*Light[3]*707)/1000;
  64. y=y+(Intensity*Light[3]*707)/1000;
  65. //5号光敏电阻,Y为0,X为正
  66. x=x+Intensity*Light[4];
  67. y=y;
  68. if(x>1000) x=1000;
  69. if(y>1000) y=1000;
  70. if(x<-1000) x=-1000;

  71. }

  72. //寻光控制运动函数
  73. /*
  74. void Find_Light()
  75. { int XY; //防止越界
  76. if (y<0) y=0;
  77. if (x>0) //右转,y为共同速度
  78. { if(x+y>1000)
  79. XY = 1000;
  80. else
  81. {XY = x+y;}
  82. TBCCR4=y;
  83. TBCCR5=0;
  84. TBCCR3=0;
  85. TBCCR2=XY;
  86. }
  87. if(x<0) //左转
  88. { x = -x;
  89. ; if(x+y>1000)
  90. XY = 1000;
  91. else
  92. XY = x+y;
  93. TBCCR4=XY;
  94. TBCCR5=0;
  95. TBCCR3=0;
  96. TBCCR2=y;
  97. }

  98. }
  99. */
  100. //备份
  101. //寻光控制运动函数
  102. void Find_Light()
  103. { int XY; //防止越界
  104. if (y<0) y=0;
  105. if (x>0) //右转,y为共同速度
  106. { if(x+y/4>1000)
  107. XY = 1000;
  108. else
  109. {XY = x+y/3;}
  110. TBCCR4=(y/2); //1.10 8:15把Y从y/3改为y/2
  111. TBCCR5=0;
  112. TBCCR3=0;
  113. TBCCR2=XY;
  114. }
  115. if(x<0) //左转
  116. { x = -x;
  117. ; if(x+y/4>1000)
  118. XY = 1000;
  119. else
  120. {XY = x+y/3;}
  121. TBCCR4=XY;
  122. TBCCR5=0;
  123. TBCCR3=0;
  124. TBCCR2=(y/2);
  125. }
  126. }

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



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

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



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



  29. void ADC12_Deal(void)
  30. {
  31. ADC12CTL0 |= ADC12SC + ENC; //开始转换
  32. }



  33. #pragma vector = ADC_VECTOR
  34. __interrupt void ADC12_IRQ(void)
  35. {

  36. ADC12CTL0 &= ~ENC ; //关闭转换
  37. Cnt_ADC12++ ;
  38. results[0] = ADC12MEM0 ; //存结果,清除IFG
  39. results[1] = ADC12MEM1 ;
  40. results[2] = ADC12MEM2 ;
  41. results[3] = ADC12MEM3 ;
  42. results[4] = ADC12MEM4 ;
  43. //results[5] = ADC12MEM5 ;
  44. //results[6] = ADC12MEM6 ;
  45. //results[7] = ADC12MEM7 ;
  46. if( Cnt_ADC12 >= (MAX_SAMPLE_TIMES+1) )
  47. {
  48. Cnt_ADC12=1;
  49. Sum_results[0] = 0;
  50. Sum_results[1] = 0;
  51. Sum_results[2] = 0;
  52. Sum_results[3] = 0;
  53. Sum_results[4] = 0;
  54. //Sum_results[5] = 0;
  55. //Sum_results[6] = 0;
  56. //Sum_results[7] = 0;
  57. }
  58. if (Cnt_ADC12 <= MAX_SAMPLE_TIMES)
  59. {

  60. Sum_results[0] += results[0];
  61. Sum_results[1] += results[1];
  62. Sum_results[2] += results[2];
  63. Sum_results[3] += results[3];
  64. Sum_results[4] += results[4];
  65. // Sum_results[5] += results[5];
  66. //Sum_results[6] += results[6];
  67. //Sum_results[7] += results[7];
  68. }
  69. if (Cnt_ADC12 == MAX_SAMPLE_TIMES)
  70. {
  71. AccessResult[0] = Sum_results[0] / MAX_SAMPLE_TIMES;
  72. AccessResult[1] = Sum_results[1] / MAX_SAMPLE_TIMES;
  73. AccessResult[2] = Sum_results[2] / MAX_SAMPLE_TIMES;
  74. AccessResult[3] = Sum_results[3] / MAX_SAMPLE_TIMES;
  75. AccessResult[4] = Sum_results[4] / MAX_SAMPLE_TIMES;
  76. //AccessResult[5] = Sum_results[5] / MAX_SAMPLE_TIMES;
  77. //AccessResult[6] = Sum_results[6] / MAX_SAMPLE_TIMES;
  78. //AccessResult[7] = Sum_results[7] / MAX_SAMPLE_TIMES;
  79. }

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

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

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

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

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

  45. char UART0_GetChar(unsigned char *Chr)
  46. {
  47. if(UART_InpLen == 0) return (0);
  48. _DINT();
  49. UART_InpLen--;
  50. *Chr = RX_BUFF[RX_IndexR];
  51. if (++RX_IndexR >= RXBUF_SIZE)
  52. { RX_IndexR = 0;
  53. }
  54. _EINT();
  55. return (1);
  56. }

  57. /*********************************************************
  58. 名称: UART0_GetCharsInRxBuf()
  59. 功能:
  60. 入口参数:
  61. 出口参数: 待读取的字节数
  62. *********************************************************/
  63. unsigned int UART0_GetCharsInRxBuf()
  64. {
  65. return (UART_InpLen);
  66. }
  67. /*********************************************************
  68. 名称: UART0_ClrRxBuf()
  69. 功能: 清除接收队列
  70. 入口参数:
  71. 出口参数:
  72. *********************************************************/

  73. void UART0_ClrRxBuf()
  74. {
  75. _DINT();
  76. UART_InpLen = 0;
  77. RX_IndexR = 0;
  78. RX_IndexW = 0;
  79. _EINT();
  80. }

  81. //串口接收中断
  82. #pragma vector= UART0RX_VECTOR
  83. __interrupt void UART0_RX (void)
  84. {
  85. UART_InpLen ++;
  86. RX_BUFF[RX_IndexW] =U0RXBUF;
  87. if (++RX_IndexW >= RXBUF_SIZE)
  88. {
  89. RX_IndexW = 0;
  90. }
  91. }

  92. /********************************************************************
  93. 名称:char UART0_PutChar()
  94. 功能:向串口发送一字节
  95. 入口参数: Chr,待发字节
  96. 出口参数: 返回1成功,0失败
  97. ********************************************************************/
  98. char UART0_PutChar(unsigned char Chr)
  99. {
  100. if(UART_OutLen == TXBUF_SIZE)
  101. {
  102. return(0);
  103. }
  104. if(UART_OutLen == 0)
  105. {
  106. IFG1 |= UTXIFG0;
  107. }
  108. _DINT();
  109. UART_OutLen++;
  110. TX_BUFF[TX_IndexW] = Chr;
  111. if (++TX_IndexW >= TXBUF_SIZE)
  112. {
  113. TX_IndexW = 0;
  114. }
  115. IE1 |= UTXIE0;
  116. _EINT();
  117. return (1);
  118. }


  119. //串口发送中断
  120. #pragma vector=UART0TX_VECTOR
  121. __interrupt void UART0_TX (void)
  122. {
  123. if(UART_OutLen>0)
  124. {
  125. UART_OutLen--;
  126. U0TXBUF = TX_BUFF[TX_IndexR];
  127. if(++TX_IndexR >= TXBUF_SIZE)
  128. {
  129. TX_IndexR = 0;
  130. }
  131. }
  132. else IE1 &=~ UTXIE0;
  133. }


 楼主| hbzjt2011 发表于 2015-6-11 11:03 | 显示全部楼层
MSP430F149 程序:
1、main.c
  1. #include "msp430x42x.h"
  2. #include "RTC.h"
  3. #include "BasicTimer.h"
  4. #include "LCD_Display.h"
  5. #include "Key.h"
  6. #include "jinshu.h"
  7. #include "UART.h"
  8. char Hour;
  9. char Minute;
  10. char Second;
  11. unsigned char Command149[5];

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

  28. unsigned int i;
  29. while(1)
  30. { for(i=0;i<20;i++)
  31. UART0_GetChar(Command149);
  32. if(Command149[0]==0x08)
  33. { Dis_Shu[3]=Dis ;
  34. _DINT();
  35. for(i=0;i<2000;i++)
  36. {
  37. Hour=RTC_GetVal('h'); //获取"时"
  38. Minute=RTC_GetVal('m'); //获取"分"
  39. Second=RTC_GetVal('s'); //获取"秒"
  40. LCD_DisplayChar(Minute/10,3);
  41. LCD_DisplayChar(Minute%10,2); //显示"分"
  42. LCD_DisplayChar(Second/10,1);
  43. LCD_DisplayChar(Second%10,0); //显示"秒"
  44. LCDM3|=0x10; //显
  45. LCD_DisplayChar(3,5);
  46. }
  47. for(i=0;i<1000;i++)
  48. { LCD_DisplayDecimal(Dis_Shu[3],2);
  49. }
  50. for(i=0;i<1000;i++)
  51. {LCD_DisplayDecimal(Dis_Shu[0],2);
  52. LCD_DisplayChar(1,5);
  53. }
  54. for(i=0;i<1000;i++)
  55. {LCD_DisplayDecimal(Dis_Shu[1],2);
  56. LCD_DisplayChar(2,5);
  57. }
  58. for(i=0;i<1000;i++)
  59. {LCD_DisplayDecimal(Dis_Shu[2],2);
  60. LCD_DisplayChar(3,5);
  61. }
  62. LCD_Clear();
  63. for(i=0;i<500;i++);
  64. }

  65. else
  66. {

  67. Hour=RTC_GetVal('h'); //获取"时"
  68. Minute=RTC_GetVal('m'); //获取"分"
  69. Second=RTC_GetVal('s'); //获取"秒"
  70. LCD_DisplayChar(Minute/10,3);
  71. LCD_DisplayChar(Minute%10,2); //显示"分"
  72. LCD_DisplayChar(Second/10,1);
  73. LCD_DisplayChar(Second%10,0); //显示"秒"
  74. LCDM3|=0x10; //显示小数点

  75. }

  76. }
  77. }
2、RTC.c
  1. #include "msp430x42x.h"

  2. unsigned char RTC_Time[7]={0,1,1,0,0,0};
  3. #define YEAR RTC_Time[0]
  4. #define MONTH RTC_Time[1]
  5. #define DATE RTC_Time[2]
  6. #define HOUR RTC_Time[3]
  7. #define MINUTE RTC_Time[4]
  8. #define SECOND RTC_Time[5]
  9. int DSEC=0;
  10. unsigned char const MONTH_Table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  11. unsigned char RTC_SR;
  12. #define DISABLE_INT; RTC_SR=__get_SR_register();_DINT(); /*关闭中断的宏定义*/
  13. #define RESTORE_INT; if(RTC_SR & GIE) _EINT(); /*恢复中断的宏定义*/
  14. /****************************************************************************
  15. * 名 称:RTC_Tick()
  16. * 功 能:对实时钟进行走时和刷新
  17. * 入口参数:Div_Sec: 定时器每秒中断的次数
  18. * 出口参数:无
  19. * 说 明: 该函数需要被周期性调用。最好放在定时中断内执行。建议使用
  20. BasicTimer定时器产生所需的定时中断。
  21. * 范 例: 在1/16秒中断内调用 RTC_Tick(16);
  22. 在5ms定时中断内调用 RTC_Tick(200);
  23. ****************************************************************************/
  24. void RTC_Tick(int DivSec)
  25. { char Days;
  26. DSEC++;
  27. DISABLE_INT; //关闭中断以免运算到一半时被中断内其他函数读取。
  28. if(DSEC >=DivSec) {SECOND++;DSEC=0;} //1秒一次
  29. if(SECOND>=60) {MINUTE++;SECOND=0;} //60秒一次
  30. if(MINUTE>=60) {HOUR++;MINUTE=0;} //60分一次
  31. if(HOUR >=24) {DATE++;HOUR=0;} //24小时一次
  32. if(MONTH==2) //处理润年2月份问题
  33. {
  34. if(YEAR%4==0) Days=29; //逢4年润二月
  35. else Days=28;
  36. }
  37. else Days=MONTH_Table[MONTH-1]; //正常月份,查表得到当月天数
  38. if(DATE >Days) {MONTH++;DATE=1;} //一个月一次
  39. if(MONTH >12) {YEAR++;MONTH=1;} //一年一次
  40. if(YEAR>=100) {YEAR=0;} //100年一次
  41. RESTORE_INT;//恢复中断
  42. }
  43. /****************************************************************************
  44. * 名 称:RTC_SetVal()
  45. * 功 能:对实时钟某个参数进行设置
  46. * 入口参数:Index: 设置内容 'Y'=年 'M'=月 'Y'=日 'h'=时 'm'=分 's'=秒
  47. Value: 设置值. 年(0~99) 月(1~12) 日(1~31) 时(0~23) 分秒(0~59)
  48. * 出口参数:返回1表示设置成功 返回0表示参数错误,设置失败
  49. * 范 例: RTC_Set('h',13); //将"时"设为13
  50. RTC_Set('m',35); //将"分"设为35
  51. ****************************************************************************/
  52. char RTC_SetVal(unsigned char Index,unsigned char Value)
  53. {
  54. switch(Index) //根据当前设置内容选择程序分支
  55. {
  56. case 'Y': if(Value>99) return(0); //设置"年"
  57. YEAR=Value; break;
  58. case 'M': if(Value>12) return(0); //设置"月"
  59. if(Value<1 ) return(0);
  60. MONTH=Value; break;
  61. case 'D': if(Value>31) return(0); //设置"日"
  62. if(Value<1 ) return(0);
  63. DATE=Value; break;
  64. case 'h': if(Value>23) return(0); //设置"时"
  65. HOUR=Value; break;
  66. case 'm': if(Value>59) return(0); //设置"分"
  67. MINUTE=Value; break;
  68. case 's': if(Value>59) return(0); //设置"秒"
  69. SECOND=Value; break;
  70. default: return(0);
  71. }
  72. return(1);
  73. }
  74. /****************************************************************************
  75. * 名 称:RTC_SetAll()
  76. * 功 能:对实时钟全部参数进行设置
  77. * 入口参数:Ptr : 数组[年月日时分秒]
  78. * 出口参数:返回1表示设置成功 返回0表示参数错误,设置失败
  79. * 范 例: RTC_SetAll(RTC_TimeArray);
  80. RTC_TimeArray是一个unsigned char 型数组,RTC_TimeArrar[0]到RTC_TimeArrar[5]
  81. 依次存放着年、月、日、时、分、秒 数据
  82. ****************************************************************************/
  83. char RTC_SetAll(unsigned char* Ptr)
  84. {
  85. char i;
  86. if(Ptr[0]>99) return(0);
  87. if(Ptr[1]>12) return(0);
  88. if(Ptr[1]<1 ) return(0);
  89. if(Ptr[2]>31) return(0);
  90. if(Ptr[2]<1 ) return(0);
  91. if(Ptr[3]>23) return(0); //排除错误参数
  92. if(Ptr[4]>59) return(0);
  93. if(Ptr[5]>59) return(0);
  94. for(i=0;i<6;i++) RTC_Time[i]=Ptr[i]; //全部复制
  95. return(1); //参数正确,返回1
  96. }
  97. /****************************************************************************
  98. * 名 称:RTC_GetVal()
  99. * 功 能:读取实时钟的某个参数
  100. * 入口参数:Index: 读取内容 'Y'=年 'M'=月 'Y'=日 'h'=时 'm'=分 's'=秒
  101. * 出口参数:读取结果。
  102. * 范 例: Hour=RTC_Get('h'); //读取当前"时"
  103. Minute=RTC_Set('m'); //读取当前"分"
  104. ****************************************************************************/
  105. char RTC_GetVal(char Index)
  106. { char Value;
  107. switch(Index) //根据当前读取内容选择程序分支
  108. {
  109. case 'Y': Value=YEAR; break; //读取"年"
  110. case 'M': Value=MONTH; break; //读取"月"
  111. case 'D': Value=DATE; break; //读取"日"
  112. case 'h': Value=HOUR; break; //读取"时"
  113. case 'm': Value=MINUTE; break; //读取"分"
  114. case 's': Value=SECOND; break; //读取"秒"
  115. default: return(255); //读取参数错误,返回255(-1)
  116. }
  117. return(Value);
  118. }
  119. /****************************************************************************
  120. * 名 称:RTC_GetAll()
  121. * 功 能:读取实时钟全部参数
  122. * 入口参数:Ptr : 数组
  123. * 出口参数:无
  124. * 说 明: 读取结果按照年月日时分秒顺序存放在传入的数组中。
  125. * 范 例: RTC_GetAll(RTC_TimeArray);
  126. RTC_TimeArray是一个unsigned char 型数组,执行后,RTC_TimeArrar[0]到
  127. RTC_TimeArrar[5] 依次存放读取的 年、月、日、时、分、秒 数据
  128. ****************************************************************************/
  129. void RTC_GetAll(char* Ptr)
  130. {
  131. char i;
  132. for(i=0;i<6;i++) Ptr[i]=RTC_Time[i]; //全部读取
  133. }
3、BasicTimer.c
  1. #include "msp430x42x.h" /*单片机寄存器头文件*/
  2. #include "RTC.h" /*实时钟头文件*/
  3. char BT_Flag=0;
  4. /****************************************************************************
  5. * 名 称:BT_Init()
  6. * 功 能:对BasicTimer进行初始化设置
  7. * 入口参数:Div_Sec: 定时器每秒产生中断次数。
  8. * 出口参数:无
  9. * 说 明: 如需使用后面的函数,在主循环之前必须先调用该初始化函数
  10. ****************************************************************************/
  11. char BT_Init(int Div_Sec)
  12. {
  13. switch(Div_Sec)
  14. {
  15. case 20: BTCTL = BTDIV+BT_fCLK2_DIV256;break; // 2s BT Int
  16. case 1: BTCTL = BTDIV+BT_fCLK2_DIV128;break; // 1s BT Int
  17. case 2: BTCTL = BTDIV+BT_fCLK2_DIV64;break; // 1/2s BT Int
  18. case 4: BTCTL = BTDIV+BT_fCLK2_DIV32;break; // 1/4s BT Int
  19. case 8: BTCTL = BTDIV+BT_fCLK2_DIV16;break; // 1/8s BT Int
  20. case 16: BTCTL = BTDIV+BT_fCLK2_DIV8;break; // 1/16s BT Int
  21. case 32: BTCTL = BTDIV+BT_fCLK2_DIV4;break; // 1/32s BT Int
  22. case 64: BTCTL = BTDIV+BT_fCLK2_DIV2;break; // 1/64s BT Int
  23. case 128:BTCTL = BT_fCLK2_DIV256;break; // 1/128s BT Int
  24. case 256:BTCTL = BT_fCLK2_DIV128;break; // 1/256s BT Int
  25. case 512:BTCTL = BT_fCLK2_DIV64;break; // 1/512s BT Int
  26. case 1024:BTCTL = BT_fCLK2_DIV32;break; // 1/1024s BT Int
  27. case 2048:BTCTL = BT_fCLK2_DIV16;break; // 1/2048s BT Int
  28. case 4096:BTCTL = BT_fCLK2_DIV8;break; // 1/4096s BT Int
  29. case 8192:BTCTL = BT_fCLK2_DIV4;break; // 1/8192s BT Int
  30. case 16384:BTCTL =BT_fCLK2_DIV2;break; // 1/16384s BT Int
  31. default : return(0);
  32. }
  33. IE2 |= BTIE; // Enable Basic Timer interrupt
  34. _EINT();
  35. return(1);
  36. }
  37. /****************************************************************************
  38. * 名 称:Cpu_SleepDelay()
  39. * 功 能:靠CPU休眠实现延迟。
  40. * 入口参数:BT_Time: BasicTimer中断次数
  41. * 出口参数:无
  42. * 说 明: 需要设置BasicTimer定时器,并开启中断。该延迟函数极省电
  43. ****************************************************************************/
  44. void Cpu_SleepDelay(int BT_Time)
  45. {
  46. for(;BT_Time>0;BT_Time--)
  47. {
  48. BT_Flag=0;
  49. while(BT_Flag==0) ;//LPM3; //只有BT中断才能唤醒CPU
  50. BT_Flag=0;
  51. }
  52. }
  53. /****************************************************************************
  54. * 名 称:Cpu_SleepWaitBT()
  55. * 功 能:CPU休眠,等待BT中断唤醒。
  56. * 入口参数:无
  57. * 出口参数:无
  58. * 说 明: 需要设置BasicTimer定时器,并开启中断。该函数极省电
  59. ****************************************************************************/
  60. void Cpu_SleepWaitBT()
  61. {
  62. BT_Flag=0;
  63. while(BT_Flag==0) ;//LPM3; //只有BT中断才能唤醒CPU
  64. BT_Flag=0;
  65. }
  66. /****************************************************************************
  67. * 名 称:BT_ISR()
  68. * 功 能:定时唤醒CPU。
  69. * 入口参数:无
  70. * 出口参数:无
  71. ****************************************************************************/
  72. #pragma vector = BASICTIMER_VECTOR
  73. __interrupt void BT_ISR(void) // 1/Div_Sec 秒一次中断(由BasicTimer所产生)
  74. {
  75. BT_Flag=1;
  76. /*
  77. 在这里写中断服务程序,如扫描键盘、实时钟走时等。
  78. */
  79. RTC_Tick(64); //RTC走时函数
  80. //__low_power_mode_off_on_exit(); //唤醒CPU
  81. }


 楼主| hbzjt2011 发表于 2015-6-11 11:05 | 显示全部楼层
4、LCD_Display.c
  1. #include "msp430x42x.h"

  2. /*宏定义,数码管a-g各段对应的比特,更换硬件只用改动以下8行*/
  3. #define d 0x01 // AAAA
  4. #define g 0x02 // F B
  5. #define b 0x04 // F B
  6. #define a 0x08 // GGGG
  7. #define DOTSEG 0x10 // E C
  8. #define e 0x20 // E C
  9. #define f 0x40 // DDDD
  10. #define c 0x80
  11. #define NEGSEG 0x02
  12. /*用宏定义自动生成段码表,很好的写法,值得学习*/
  13. /*更换硬件无需重写段码表*/
  14. const char LCD_Tab[] = {
  15. a + b + c + d + e + f, // Displays "0"
  16. b + c, // Displays "1"
  17. a + b + d + e + g, // Displays "2"
  18. a + b + c + d + g, // Displays "3"
  19. b + c + f + g, // Displays "4"
  20. a + c + d + f +g, // Displays "5"
  21. a + c + d + e + f + g, // Displays "6"
  22. a + b + c, // Displays "7"
  23. a + b + c + d + e + f + g, // Displays "8"
  24. a + b + c + d + f + g, // Displays "9"
  25. a + b + c + e + f + g, // Displays "A"
  26. c + d + e + f + g, // Displays "B"
  27. a + d + e + f,         // Displays "C"
  28. b + c + d + e + g, // Displays "D"
  29. a + d + e + f + g, // Displays "E"
  30. a + e + f + g,         // Displays "F"
  31. a + c + d + e + f, // Displays "G"
  32. b + c + e + f + g, // Displays "H"
  33. e + f, // Displays "I"
  34. b + c + d + e, // Displays "J"
  35. b + d + e + f + g, // Displays "K"
  36. d + e + f, // Displays "L"
  37. a + c + e + g, // Displays "M"
  38. a + b + c + e + f, // Displays "N"
  39. c + e + g, // Displays "n"
  40. c + d + e + g, // Displays "o"
  41. a + b + c + d + e + f, // Displays "O"
  42. a + b + e + f + g, // Displays "P"
  43. a + b + c + f + g, // Displays "Q"
  44. e + g,         // Displays "r"
  45. a + c + d + f +g, // Displays "S"
  46. d + e + f + g, // Displays "t"
  47. a + e + f , // Displays "T"
  48. b + c + d + e + f, // Displays "U"
  49. c + d + e, // Displays "v"
  50. b + d + f + g, // Displays "W"
  51. b + c + d + f + g, // Displays "Y"
  52. a + b + d + e + g, // Displays "Z"
  53. g, // Displays "-"
  54. b, // Displays "'"
  55. 0         // Displays " "
  56. };
  57. #undef a
  58. #undef b
  59. #undef c
  60. #undef d
  61. #undef e
  62. #undef f
  63. #undef g

  64. #define AA 10
  65. #define BB AA+1
  66. #define CC BB+1
  67. #define DD CC+1
  68. #define EE DD+1
  69. #define FF EE+1
  70. #define GG FF+1
  71. #define HH GG+1
  72. #define II HH+1
  73. #define JJ II+1
  74. #define KK JJ+1
  75. #define LL KK+1
  76. #define mm LL+1
  77. #define NN mm+1
  78. #define nn NN+1
  79. #define oo nn+1
  80. #define OO oo+1
  81. #define PP OO+1
  82. #define QQ PP+1
  83. #define rr QQ+1
  84. #define SS rr+1
  85. #define tt SS+1
  86. #define TT tt+1
  87. #define UU TT+1
  88. #define VV UU+1
  89. #define WW VV+1
  90. #define YY WW+1
  91. #define ZZ YY+1
  92. #define BR ZZ+1 /* - */
  93. #define DT BR+1 /* ' */
  94. #define SP DT+1 /* 空白 */

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

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

  128. if(Number<0) {Number=-Number; Neg=1;} //处理负数
  129. else Neg=0;
  130. for(i=0;i<7;i++) //拆分数字
  131. {
  132. DispBuff[i]=Number%10;
  133. Number/=10;
  134. }
  135. for(i=6;i>DOT;i--) //消隐无效"0"
  136. {
  137. if (DispBuff[i]==0) DispBuff[i]=SP;
  138. else break;
  139. }
  140. PolarLocate=i+1; // 负号显示在第一个有效数字左边
  141. if(DOT>3) DOT=255; // 无效的小数点不显示
  142. if(DOT<1) DOT=255; // LCD048段码中只有123位数字有小数点
  143. for(i=0;i<7;i++)
  144. {
  145. temp=LCD_Tab[DispBuff[i]]; //查表
  146. if (DOT==i) temp|=DOTSEG;//显示小数点
  147. if ((PolarLocate==i)&&(Neg)) temp|=NEGSEG;//负号
  148. pLCD[i]=temp; //写入显存
  149. }
  150. }
  151. /****************************************************************************
  152. * 名 称:LCD_DisplayDecimal()
  153. * 功 能:在LCD上显示一个带有小数点的短整型数据。
  154. * 入口参数:Number:显示数值 (-32768~32767)
  155. DOT :小数点位数(0~3)
  156. * 出口参数:无
  157. * 范 例: LCD_DisplayDecimal( 12345,2); 显示结果: 123.45 (2位小数)
  158. LCD_DisplayDecimal(-12345,1); 显示结果:-1234.5 (1位小数)
  159. * 说 明: 该函数显示数值范围小,但执行时间短,耗电小。
  160. ****************************************************************************/
  161. void LCD_DisplayDecimal( int Number, char DOT)
  162. {
  163. char Neg;
  164. char i;unsigned char temp;
  165. char *pLCD = (char *)&LCDM1;
  166. char PolarLocate;
  167. char DispBuff[8];

  168. if(Number<0) {Number=-Number; Neg=1;} //处理负数
  169. else Neg=0;
  170. for(i=0;i<7;i++) //拆分数字
  171. {
  172. DispBuff[i]=Number%10;
  173. Number/=10;
  174. }
  175. for(i=6;i>DOT;i--) //消隐无效"0"
  176. {
  177. if (DispBuff[i]==0) DispBuff[i]=SP;
  178. else break;
  179. }
  180. PolarLocate=i+1; // 负号显示在第一个有效数字左边
  181. if(DOT>3) DOT=255; // 无效的小数点不显示
  182. if(DOT<1) DOT=255; // LCD048段码中只有123位数字有小数点
  183. for(i=0;i<7;i++)
  184. {
  185. temp=LCD_Tab[DispBuff[i]]; //查表
  186. if (DOT==i) temp|=DOTSEG;//显示小数点
  187. if ((PolarLocate==i)&&(Neg)) temp|=NEGSEG;//负号
  188. pLCD[i]=temp; //写入显存
  189. }
  190. }

  191. /****************************************************************************
  192. * 名 称:LCD_DisplayLongNumber()
  193. * 功 能:在LCD上显示一个长整数。
  194. * 入口参数:Number:显示数值 (-999999~9999999)
  195. * 出口参数:无
  196. * 范 例: LCD_DisplayNumber( 123456); 显示结果: 123456
  197. LCD_DisplayNumber(-123456); 显示结果:-123456
  198. * 说 明: 该函数能够显示满屏7位数字,但执行时间较长,耗电大。
  199. ****************************************************************************/
  200. void LCD_DisplayLongNumber(long int Number)
  201. {
  202. LCD_DisplayLongDecimal(Number,0) ;//整数没有小数点
  203. }
  204. /****************************************************************************
  205. * 名 称:LCD_DisplayNumber()
  206. * 功 能:在LCD上显示一个短整数。
  207. * 入口参数:Number:显示数值 (-32768~32767)
  208. * 出口参数:无
  209. * 范 例: LCD_DisplayNumber( 12345); 显示结果: 12345
  210. LCD_DisplayNumber(-12345); 显示结果:-12345
  211. ****************************************************************************/
  212. void LCD_DisplayNumber(int Number)
  213. {
  214. LCD_DisplayDecimal(Number,0) ;//整数没有小数点
  215. }
  216. /****************************************************************************
  217. * 名 称:LCD_DisplayChar()
  218. * 功 能:在LCD上显示一个字符。
  219. * 入口参数:ch :显示内容 可显示字母请参考LCD_Display.h中的宏定义
  220. Location:显示位置 从左至右对应76543210
  221. * 出口参数:无
  222. * 说 明: 调用该函数不影响LCD其他位的显示。但显示数字的函数会覆盖该函数的结
  223. 果,因此该函数要在显示数据函数之后调用。
  224. * 范 例: LCD_DisplayChar(AA,4);
  225. LCD_DisplayChar(PP,5);
  226. LCD_DisplayChar(2 ,6); 显示结果: 2PAXXXX
  227. ****************************************************************************/
  228. void LCD_DisplayChar(char ch,char Location)
  229. {
  230. char *pLCD = (char *)&LCDM1;
  231. pLCD[Location]=LCD_Tab[ch];
  232. }
  233. /****************************************************************************
  234. * 名 称:LCD_InsertChar()
  235. * 功 能:在LCD最右端插入一个字符。
  236. * 入口参数:ch :插入字符 可显示字母请参考LCD_Display.h中的宏定义
  237. * 出口参数:无
  238. * 说 明: 调用该函数后,LCD所有已显示字符左移一位,新的字符插入在最右端一位。
  239. 该函数可以实现滚屏动画效果,或用于在数据后面显示单位。
  240. * 范 例: LCD_DisplayDecimal(1234,1);
  241. LCD_InsertChar(PP);
  242. LCD_InsertChar(FF);显示结果: 123.4PF

  243. ****************************************************************************/
  244. void LCD_InsertChar(char ch)
  245. { char i;
  246. char *pLCD = (char *)&LCDM1;
  247. for(i=6;i>=1;i--) pLCD[i]=pLCD[i-1];
  248. pLCD[0]=LCD_Tab[ch];
  249. }
  250. /****************************************************************************
  251. * 名 称:LCD_ON()
  252. * 功 能:开启LCD显示
  253. * 入口参数:无
  254. * 出口参数:无
  255. * 说 明: 调用该函数将开启LCD显示。开启后LCD仍显示最后一次显示内容
  256. ****************************************************************************/
  257. void LCD_ON()
  258. {
  259. LCDCTL |= LCDON;
  260. }
  261. /****************************************************************************
  262. * 名 称:LCD_ON()
  263. * 功 能:关闭LCD显示
  264. * 入口参数:无
  265. * 出口参数:无
  266. * 说 明: 调用该函数将关闭LCD显示,可节省3~5uA电流。该函数不清除显示内容。
  267. ****************************************************************************/
  268. void LCD_OFF()
  269. {
  270. LCDCTL &=~ LCDON;
  271. }

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

  7. char P_KEY1=255; //存放KEY1前一次状态的变量
  8. char N_KEY1=255; //存放KEY1当前状态的变量
  9. char P_KEY2=255; //存放KEY2前一次状态的变量
  10. char N_KEY2=255; //存放KEY2当前状态的变量
  11. char P_KEY3=255; //存放KEY3前一次状态的变量
  12. char N_KEY3=255; //存放KEY3当前状态的变量



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

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

  19. unsigned char KEY_SR;
  20. #define DISABLE_INT; KEY_SR=__get_SR_register();_DINT();
  21. #define RESTORE_INT; if(KEY_SR & GIE) _EINT();
  22. /****************************************************************************
  23. * 名 称:Key_Init()
  24. * 功 能:初始化键盘所在的IO口
  25. * 入口参数:无
  26. * 出口参数:无
  27. ****************************************************************************/
  28. void Key_Init()
  29. {
  30. P1DIR&=~(BIT5+BIT6+BIT7); //P1.5/6/7作为输入
  31. }
  32. /****************************************************************************
  33. * 名 称:Key_InBuff()
  34. * 功 能:将一次键值压入键盘缓冲队列
  35. * 入口参数:Key:被压入缓冲队列的键值
  36. * 出口参数:无
  37. ****************************************************************************/
  38. void Key_InBuff(char Key)
  39. {
  40. if(Key_Count>=KEYBUFF_SIZE) return;//若缓冲区已满,放弃本次按键
  41. DISABLE_INT;
  42. Key_Count++; //按键次数计数增加
  43. KeyBuff[Key_IndexW] = Key; //从队列头部追加新的数据
  44. if (++Key_IndexW >= KEYBUFF_SIZE) //循环队列,如果队列头指针越界
  45. {
  46. Key_IndexW = 0; //队列头指针回到数组起始位置
  47. }
  48. RESTORE_INT;
  49. }
  50. /****************************************************************************
  51. * 名 称:Key_GetKey()
  52. * 功 能:从键盘缓冲队列内读取一次键值
  53. * 入口参数:无
  54. * 出口参数:若无按键,返回0,否则返回一次按键键值。
  55. * 说 明: 调用一次该函数,会自动删除缓冲队列里一次按键键值。
  56. ****************************************************************************/
  57. char Key_GetKey()
  58. { char Key;
  59. if(Key_Count==0) return(0); //若无按键,返回0
  60. DISABLE_INT;//队列操作过程中不允许被定时中断执行ScanIO函数,保护全局变量正确
  61. Key_Count--; //按键次数计数减1
  62. Key=KeyBuff[Key_IndexR]; //从缓冲区尾部读取一个按键值
  63. if (++Key_IndexR >= KEYBUFF_SIZE)//循环队列,如果队列尾指针越界
  64. {
  65. Key_IndexR = 0; //队列尾指针回到数组起始位置
  66. }
  67. RESTORE_INT; //恢复中断允许
  68. return(Key);
  69. }
  70. /****************************************************************************
  71. * 名 称:Key_WaitKey()
  72. * 功 能:从键盘缓冲队列内读取一次键值
  73. * 入口参数:无
  74. * 出口参数:若有按键,返回键值,否则等待按键。
  75. * 说 明: 该函数会阻塞CPU继续执行后面的程序,应用时需注意。
  76. ****************************************************************************/
  77. char Key_WaitKey()
  78. { char Key;
  79. while(1)
  80. {
  81. Key=Key_GetKey(); //从键盘缓冲队列读取一次键值
  82. if(Key==0) LPM3; //如果没按键,则停止CPU,等待被唤醒继续读按键
  83. else return(Key); //如果有按键,则返回键值
  84. }
  85. }

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

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

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

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

  105. }
6、jinshu.c
  1. #include "msp430x42x.h"
  2. #include "Uart.h"
  3. #include "LCD_Display.h"
  4. #include "RTC.h"

  5. #define Circle 46
  6. char Jinshu_Shu;//定义检测到金属的片数
  7. unsigned int TA_Overflowcnt;
  8. unsigned long int period;
  9. unsigned int Dis;
  10. unsigned int cnt;
  11. extern char Second;
  12. unsigned int Dis_Shu[4];
  13. void jinshu_Init(void) //金属检测初始化程序
  14. {
  15. Jinshu_Shu=0; //初始化 检测到金属的片数为零

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

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

  36. P1IFG=0;
  37. if(Jinshu_Shu==3)
  38. {for(i=0;i<5;i++)
  39. UART0_PutChar(0x02); //停车
  40. }
  41. else
  42. {for(i=0;i<5;i++)
  43. UART0_PutChar(0x01);
  44. }
  45. //LCD_DisplayDecimal(Dis,2);

  46. //可以在这里调用串口通信程序,向MSP149发送信息,打开声光指示程序
  47. }
  48. }
  49. // 与测速有关的部分
  50. _BIC_SR(SCG0);
  51. if((P1IN&BIT5)==BIT5)
  52. {
  53. P1IFG=0;
  54. //return;
  55. }
  56. if (P1IFG & BIT5);
  57. for(j=0;j<2000;j++)
  58. if (P1IFG & BIT5);
  59. {
  60. cnt++;
  61. Dis = cnt * Circle;
  62. //LCD_DisplayDecimal(Dis,1);

  63. }
  64. P1IFG=0;

  65. }

  66. #pragma vector=TIMERA1_VECTOR
  67. __interrupt void TA_ISR(void)
  68. {
  69. switch(TAIV)
  70. {
  71. case 2:break;
  72. case 4:break;
  73. case 10:TA_Overflowcnt++;
  74. break;
  75. }
  76. }
7、UART.c
  1. #include <msp430x14x.h>
  2. #define RXBUF_SIZE 32
  3. #define TXBUF_SIZE 32 //发送FIFO的最大容量

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

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

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

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

  45. char UART0_GetChar(unsigned char *Chr)
  46. {
  47. if(UART_InpLen == 0) return (0);
  48. _DINT();
  49. UART_InpLen--;
  50. *Chr = RX_BUFF[RX_IndexR];
  51. if (++RX_IndexR >= RXBUF_SIZE)
  52. { RX_IndexR = 0;
  53. }
  54. _EINT();
  55. return (1);
  56. }

  57. /*********************************************************
  58. 名称: UART0_GetCharsInRxBuf()
  59. 功能:
  60. 入口参数:
  61. 出口参数: 待读取的字节数
  62. *********************************************************/
  63. unsigned int UART0_GetCharsInRxBuf()
  64. {
  65. return (UART_InpLen);
  66. }
  67. /*********************************************************
  68. 名称: UART0_ClrRxBuf()
  69. 功能: 清除接收队列
  70. 入口参数:
  71. 出口参数:
  72. *********************************************************/

  73. void UART0_ClrRxBuf()
  74. {
  75. _DINT();
  76. UART_InpLen = 0;
  77. RX_IndexR = 0;
  78. RX_IndexW = 0;
  79. _EINT();
  80. }

  81. //串口接收中断
  82. #pragma vector= UART0RX_VECTOR
  83. __interrupt void UART0_RX (void)
  84. {
  85. UART_InpLen ++;
  86. RX_BUFF[RX_IndexW] =U0RXBUF;
  87. if (++RX_IndexW >= RXBUF_SIZE)
  88. {
  89. RX_IndexW = 0;
  90. }
  91. }

  92. /********************************************************************
  93. 名称:char UART0_PutChar()
  94. 功能:向串口发送一字节
  95. 入口参数: Chr,待发字节
  96. 出口参数: 返回1成功,0失败
  97. ********************************************************************/
  98. char UART0_PutChar(unsigned char Chr)
  99. {
  100. if(UART_OutLen == TXBUF_SIZE)
  101. {
  102. return(0);
  103. }
  104. if(UART_OutLen == 0)
  105. {
  106. IFG1 |= UTXIFG0;
  107. }
  108. _DINT();
  109. UART_OutLen++;
  110. TX_BUFF[TX_IndexW] = Chr;
  111. if (++TX_IndexW >= TXBUF_SIZE)
  112. {
  113. TX_IndexW = 0;
  114. }
  115. IE1 |= UTXIE0;
  116. _EINT();
  117. return (1);
  118. }


  119. //串口发送中断
  120. #pragma vector=UART0TX_VECTOR
  121. __interrupt void UART0_TX (void)
  122. {
  123. if(UART_OutLen>0)
  124. {
  125. UART_OutLen--;
  126. U0TXBUF = TX_BUFF[TX_IndexR];
  127. if(++TX_IndexR >= TXBUF_SIZE)
  128. {
  129. TX_IndexR = 0;
  130. }
  131. }
  132. else IE1 &=~ UTXIE0;
  133. }


FireRiver9 发表于 2015-6-11 21:05 | 显示全部楼层
楼主大神,mark
 楼主| hbzjt2011 发表于 2015-6-11 21:41 | 显示全部楼层

共同学习,共同进步!
冰河w 发表于 2015-6-12 20:30 | 显示全部楼层
好资料,必须mark
comeon201208 发表于 2015-6-13 20:30 | 显示全部楼层
以MSP超低功耗单片机系列MSP430F149和MSP430FE425为核心,完成小车的寻迹、检测金属、避障、寻光、测速等功能。
comeon201208 发表于 2015-6-13 20:31 | 显示全部楼层
在机械结构上,对普通的小车作了改进,即用一个万用轮来代替两个前轮,使小车的转向更加灵敏。采用PWM 驱动芯片控制电机,红外传感器检测黑线,金属传感器检测铁片,光敏器件检测光强,红外 LED 和一体化接收头来避障。
lwsn 发表于 2015-6-25 21:25 | 显示全部楼层
楼主的检测金属模块是怎么做的
yf201306 发表于 2016-4-10 16:46 | 显示全部楼层
楼主能不能将原理图发给我,详细一点的(主要是付的图片不清晰),还有就是那两个单片机怎么通信,邮箱:1913874509@qq.com
蔬木果 发表于 2018-7-7 00:13 | 显示全部楼层
学习了,mark。
pmp 发表于 2018-7-13 13:41 | 显示全部楼层
以为是平衡车的设计呢。
vivilzb1985 发表于 2018-7-16 10:11 | 显示全部楼层
以MSP超低功耗单片机系列MSP430F149和MSP430FE425为核心,完成寻迹、检测金属、避障、寻光、测速等功能。
shenmu2012 发表于 2018-7-16 22:03 | 显示全部楼层
采用PWM 驱动芯片控制电机,红外传感器检测黑线,金属传感器检测铁片,光敏器件检测光强,红外 LED 和一体化接收头来避障。
shenmu2012 发表于 2018-7-16 22:03 | 显示全部楼层
对电机的控制还是采用PWM的信号的哈
quickman 发表于 2018-7-16 22:08 | 显示全部楼层
jstgotodo 发表于 2018-7-16 22:08 | 显示全部楼层
做个平衡车吧。
iamaiqiyi 发表于 2018-7-16 22:08 | 显示全部楼层
简易智能电动怎样
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

323

主题

2908

帖子

45

粉丝
快速回复 在线客服 返回列表 返回顶部