【TI 技术资料分享】+基于Launchpad的爱情万年历

[复制链接]
2133|13
 楼主| dirtwillfly 发表于 2015-1-23 22:20 | 显示全部楼层 |阅读模式
一、硬件:
1、 launchpad开发板一块(板载MSP430G2553)
2、 LCD1602液晶屏一块(3.3V
3、 DS1302数字时钟芯片
4、 32.768KHz晶振一枚
5、 按键两枚
6、 电位器一枚
    7、 电容、导线等
二、要实现的功能:
1、 精确显示年月日时分秒
2、 闰年、二月自动调节时间
3、 两个按键控制调节时间日期等
4、 显示自定义的语句
    5、 恋爱纪念日提醒,显示不一样的画面(We’ve been together for XX years!)
三、硬件电路图


四、整体思路
//设置P1口作为输出连接LCD1602的数据端D0-D7,P2.0为rs,P2.1为rw,P2.2为e(都配置为输出)作为LCD1602的控制端口。
//配置P2.3为SCLK,P2.4为SDA,P2.5为RST(都配置为输出)作为DS1302的控制端
//P2.6、P2.7接两个按键,配置为输入,下降沿中断,中断处理函数 void key_pro(),P2、6接key1(控制光标),P2.7接key2,控制调节
//grace配置中设置P2.0---P2.5为输出,MCLK=1MHz,关闭看门狗
//在做DS1302的硬件时应该特别注意:数据线RST、SCLK、SDA一定上拉电阻,晶振添加负载电容,连接线尽量短
先列写出主函数,是思路清晰点:
  1. void main (void)
  2. {
  3. CSL_init(); // 初始化单片机
  4. lsd1602_init(); // 初始化LCD1602
  5. ds1302_init(); //初始化DS1302
  6. while(1)
  7. {
  8. _DINT(); //关闭中断
  9. data_pro(); //从DS1302中读取并处理数据
  10. _EINT();
  11. if(month== 0x03 && date== 0x07)//3月7日是我们的纪念日
  12. jww(); //如果是3月7号则显示不同的画面(jww是处理函数)
  13. update_disbuf(); //更新LCD1602显示空间(在2553中开辟)
  14. display(); //控制LCD1602显示时间
  15. if(month== 0x03 && date== 0x07)//3月7日纪念日
  16. __delay_cycles(1000000);
  17. }
  18. }
就这样很简单的思路,全部使用了子程序调用,所以看起来清晰点,下面贴出来整个函数。注释的挺多了,有什么建议或者交流的直接回复帖子。
五、程序
说一下阅读方法,先看懂了上边的主函数,然后对应主函数调用的子函数,一个一个来看,逐个看懂,就很简单。(有一个难点,就是按键处理。因为只用了两个按键,key1每按一次会有全局变量i增加一,控制LCD1602光标的显示位置,另外一个按键调节时间)

  1. //设置P0作为输出连接LCD1602的数据端D0-D7,P2.3为SCLK,P2.4为SDA,P2.5为RST(都配置为输出)
  2. //P2.0为rs,P2.1为rw,P2.2为e(都配置为输出)
  3. //P2.67配置为输入,下降沿中断,中断处理函数 void key_pro(),P2。6接key1(控制光标),P2.7接key2,控制调节(增加)
  4. //grace配置中设置P2.345为输出,MCLK=1MHz,
  5. //本程序将数据用ASCII表示,方便LCD1602显示
  6. //在做DS1302的硬件时应该特别注意:数据线RST。SCLK、SDA一定上拉电阻,晶振添加负载电容,连接线尽量短
  7. //date代表日,day代表星期几
  8. #include <msp430.h>
  9. #include <ti/mcu/msp430/csl/CSL.h>
  10. //定义全局变量年月日时分秒
  11. char year,month,date,hour,minute,second,n;//n代表周几
  12. char love_years; //恋爱纪念年
  13. char day[7][3]={"MON","TUE","WED","THI","FRI","SAT","SUN"};
  14. char i=0; //用来记录key1按下的次数
  15. char dis_buf1[16]; //lcd上排显示缓冲区
  16. char dis_buf2[16]; //lcd下排显示缓冲区
  17. char weiwei1[16]={"weiwei: I love u"};
  18. char weiwei2[16]={"so much! by xuxu"};
  19. char love1[16]={"We've been toget"};
  20. char love2[16]={"her for years"};
  21. //LCD1602控制位
  22. #define rs_0 (P2OUT &= ~BIT0)
  23. #define rs_1 (P2OUT |= BIT0)
  24. #define rw_0 (P2OUT &= ~BIT1)
  25. #define rw_1 (P2OUT |= BIT1)
  26. #define e_0 (P2OUT &= ~BIT2)
  27. #define e_1 (P2OUT |= BIT2)
  28. //DS1302控制位
  29. #define SCLK_0 (P2OUT &= ~BIT3)
  30. #define SCLK_1 (P2OUT |= BIT3)
  31. #define SDA_0 (P2OUT &= ~BIT4)
  32. #define SDA_1 (P2OUT |= BIT4)
  33. #define RST_0 (P2OUT &= ~BIT5)
  34. #define RST_1 (P2OUT |= BIT5)
  35. #define SDA (P2IN &= BIT4)
  36. //宏定义DS1302数据地址
  37. #define write_second 0x80
  38. #define read_second 0x81
  39. #define write_minute 0x82
  40. #define read_minute 0x83
  41. #define write_hour 0x84
  42. #define read_hour 0x85
  43. #define write_date 0x86
  44. #define read_date 0x87
  45. #define write_month 0x88
  46. #define read_month 0x89
  47. #define write_year 0x8c
  48. #define read_year 0x8d
  49. #define write_day 0x8a
  50. #define read_day 0x8b
  51. #define write_protect 0x8e
  52. #define write_power 0x90
  53. //*******************以下为LCD1602的子函数************************//
  54. //***********************************************************//
  55. //查询是否忙碌(每次输入指令前都要判断液晶模块是否处于忙的状态)
  56. char busy(void)
  57. {
  58. char busyc;
  59. rs_0;
  60. rw_1;
  61. e_1;
  62. __delay_cycles(1000);
  63. P1DIR = 0x00; //P1口置为输入,读取LCD状态
  64. busyc = P1IN & BIT7; //从P1输入是否忙碌(D7高电平表示忙碌)
  65. P1DIR = 0xff;
  66. e_0;
  67. return busyc;
  68. }
  69. //向LCD1602写字节命令
  70. void write_command(char command)
  71. {
  72. while(busy()); //判断LCD是否忙碌
  73. rs_0;
  74. rw_0;
  75. P1OUT = command;
  76. __delay_cycles(1); //时间间隔MIN=30nS
  77. e_1;
  78. __delay_cycles(1); //MIN=150nS
  79. e_0;
  80. }
  81. //向LCD1602写数据命令
  82. void write_data(char data)
  83. {
  84. while(busy()); //判断LCD是否忙碌
  85. rs_1;
  86. rw_0;
  87. __delay_cycles(1);
  88. e_1;
  89. P1OUT=data;
  90. __delay_cycles(1);
  91. e_0;
  92. }
  93. //LCD1602初始化函数
  94. void lsd1602_init()
  95. {
  96. e_0;
  97. write_command(0x38);
  98. __delay_cycles(15000);
  99. write_command(0x0c);
  100. write_command(0x06);
  101. write_command(0x01);
  102. }
  103. void update_disbuf()
  104. {
  105. dis_buf1[0]='2';
  106. dis_buf1[1]='0';
  107. dis_buf1[2]=year/16 + 0x30;
  108. dis_buf1[3]=year%16 + 0x30;
  109. dis_buf1[4]='-';
  110. dis_buf1[5]=month/16 + 0x30;
  111. dis_buf1[6]=month%16 + 0x30;
  112. dis_buf1[7]='-';
  113. dis_buf1[8]=date/16 + 0x30;
  114. dis_buf1[9]=date%16 + 0x30;
  115. dis_buf1[10]=' ';
  116. dis_buf1[11]=' ';
  117. dis_buf1[12]=' ';
  118. dis_buf1[13]=day[n-1][0];
  119. dis_buf1[14]=day[n-1][1];
  120. dis_buf1[15]=day[n-1][2];
  121. dis_buf2[0]=' ';
  122. dis_buf2[1]='j';
  123. dis_buf2[2]='w';
  124. dis_buf2[3]='w';
  125. dis_buf2[4]='&';
  126. dis_buf2[5]='z';
  127. dis_buf2[6]='x';
  128. dis_buf2[7]=' ';
  129. dis_buf2[8]=hour/16 + 0x30;
  130. dis_buf2[9]=hour%16 + 0x30;
  131. dis_buf2[10]=':';
  132. dis_buf2[11]=minute/16 + 0x30;
  133. dis_buf2[12]=minute%16 + 0x30;
  134. dis_buf2[13]=':';
  135. dis_buf2[14]=second/16 + 0x30;
  136. dis_buf2[15]=second%16 + 0x30;
  137. }
  138. void display()
  139. {
  140. char t;
  141. write_command(0x80);
  142. for (t=0;t<=15;t++)
  143. {write_data(dis_buf1[t]);}
  144. write_command(0xc0);
  145. for (t=0;t<=15;t++)
  146. {write_data(dis_buf2[t]);}
  147. }
  148. //********************以下为DS1302的子函数************************//
  149. //***********************************************************//
  150. //向DS1302写一个字节的数据
  151. void ds1302_Wbyte(char dat)
  152. {
  153. char s,temp;
  154. temp = dat;
  155. for(s=0;s<8;s++)
  156. {if(temp & 0x01) //从低位开始传输数据
  157. {SDA_1;}
  158. else
  159. SDA_0;
  160. SCLK_1; //上升沿锁存数据
  161. temp = temp>>1; //数据右移一位为下次输出做准备
  162. SCLK_0; //为下一次做准备
  163. }
  164. }
  165. //从DS1302读取8位数据
  166. char ds1302_Rbyte()
  167. {
  168. char u,temp;
  169. P2DIR &= ~BIT4;
  170. for(u=8; u>0;u--)
  171. {
  172. temp=temp>>1;
  173. temp += (P2IN&BIT4)<<3;
  174. SCLK_1;
  175. SCLK_0;
  176. }
  177. P2DIR |= BIT4;
  178. return(temp);
  179. }
  180. //向DS1302写入地址然后读取数据
  181. char ds1302_Read(char cmd)
  182. {
  183. char dat;
  184. RST_0; //初始化RST为低
  185. SCLK_0; //SLK=0
  186. RST_1; //开始传输数据
  187. ds1302_Wbyte(cmd); //传输命令字,写入要读取的时间、日期地址
  188. dat = ds1302_Rbyte(); //读取八位数据
  189. RST_0; //结束数据传输
  190. SCLK_0; //拉高时钟线
  191. return(dat);
  192. }
  193. //向DS1302写入地址后写入数据
  194. void ds1302_Write(char cmd,char dat)
  195. {
  196. RST_0;
  197. SCLK_0; //在RST的上升沿,SCLK必须为0
  198. RST_1; //开始传输数据
  199. ds1302_Wbyte(cmd); //写入要修改的地址
  200. ds1302_Wbyte(dat); //写入数据
  201. SCLK_1; //拉高时钟线
  202. RST_0; //拉低RST
  203. }
  204. //初始化DS1302的程序
  205. void ds1302_init(void)
  206. {
  207. ds1302_Write(write_protect,0x00);//关闭写保护
  208. ds1302_Write(write_second,0x00); //初始化秒为00,不暂停时钟(BIT7)
  209. ds1302_Write(write_minute,0x59); //初始化分为00
  210. ds1302_Write(write_hour,0x23); //初始化时为23,设置为24小时制(BIT7)
  211. ds1302_Write(write_date,0x01); //初始化日期为01
  212. ds1302_Write(write_month,0x01); //初始化月为01
  213. ds1302_Write(write_year,0x12); //初始化年为(20)12
  214. ds1302_Write(write_day,0x07); //周日
  215. ds1302_Write(write_power,0x0a5); //一个二极管压降,电阻4K
  216. ds1302_Write(write_protect,0x80);//打开写保护
  217. }
  218. //DS1302数据处理函数,此函数将个位、十位分别用char表示,方便用数码管显示
  219. void data_pro(void)
  220. {
  221. ds1302_Write(write_protect,0x00);//关闭写保护
  222. date = ds1302_Read(read_date); //读取日
  223. if(date>0x29 && month==0x02) //如果调时时2月超过29
  224. {ds1302_Write(write_date,0x01);
  225. date = ds1302_Read(read_date);
  226. ds1302_Write(write_month,month + 1);
  227. }
  228. month = ds1302_Read(read_month);//读取月
  229. year = ds1302_Read(read_year); //读取年
  230. hour = ds1302_Read(read_hour); //读取时
  231. hour = hour & 0x3f; //屏蔽掉前两位
  232. minute = ds1302_Read(read_minute);//读取分
  233. second = ds1302_Read(read_second);//读取秒
  234. n = ds1302_Read(read_day);//读取星期
  235. ds1302_Write(write_protect,0x80);//打开写保护
  236. }
  237. //按键中断处理程序(使用grace配置)
  238. void key_pro(void)
  239. {
  240. char j; //用于复制自定义的显示计数(16个)
  241. __delay_cycles(8000); //延时去抖动
  242. if(!(P2IN & BIT6)) //判断是否有按键按下
  243. {
  244. i++;
  245. switch(i)
  246. {
  247. case 1:
  248. write_command(0x83); //显示光标到年
  249. write_command(0x0f);
  250. break;
  251. case 2:
  252. write_command(0x86); //显示光标到月
  253. write_command(0x0f);
  254. break;
  255. case 3:
  256. write_command(0x89); //显示光标到日
  257. write_command(0x0f);
  258. break;
  259. case 4:
  260. write_command(0x8f); //显示光标到周
  261. write_command(0x0f);
  262. break;
  263. case 5:
  264. write_command(0xc9); //显示光标到时
  265. write_command(0x0f);
  266. break;
  267. case 6:
  268. write_command(0xcc); //显示光标到分
  269. write_command(0x0f);
  270. break;
  271. case 7:
  272. write_command(0xcf); //显示光标到秒
  273. write_command(0x0f);
  274. break;
  275. default: break;
  276. }
  277. }
  278. if(i>7)
  279. {
  280. i=0;
  281. write_command(0x0c); //关闭光标显示
  282. }
  283. P2IFG=0; //软件复位标志
  284. while(!(P2IN & BIT6))
  285. {
  286. ds1302_Write(write_protect,0x00);//关闭写保护
  287. while(!(P2IN & BIT7)) //如果按键2被按下
  288. {
  289. switch(i) //根据i的值来确定某变量进行加1
  290. {case 0: //显示自定义的语句
  291. for(j=0;j<16;j++)
  292. {
  293. dis_buf1[j] = weiwei1[j];
  294. dis_buf2[j] = weiwei2[j];
  295. display();
  296. }
  297. break;
  298. case 1: //此事处理全局变量year
  299. year++; //year加1
  300. if(year>0x99) //如果year大于99则置0
  301. year=0;
  302. if((year & 0x0f)>0x09) //如果year低四位大于9(第四位BCD码表示个位),十位加1,个位置0
  303. {year +=0x10;
  304. year &=0xf0;
  305. }
  306. ds1302_Write(write_year,year);//将变化后的year写入DS1302
  307. year = ds1302_Read(read_year);//读出来year显示(使调节year时同步变化,为了人性化)
  308. update_disbuf(); //更新显示字符
  309. while(!(P2IN & BIT7))
  310. display();
  311. break;
  312. case 2: //此时处理全局变量month
  313. month++;
  314. if(month>0x12)
  315. month=1;
  316. if((month & 0x0f)>0x09)
  317. {month +=0x10;
  318. month &=0xf0;
  319. }
  320. ds1302_Write(write_month,month);
  321. month = ds1302_Read(read_month);
  322. update_disbuf(); //更新显示字符
  323. while(!(P2IN & BIT7))
  324. display();
  325. break;
  326. case 3: //此时处理全局变量date
  327. date++;
  328. if( (date>0x29 && month==0x02)
  329. || (month==0x04 || month==0x06 || month==0x09 || month==0x11)&& date>0x30
  330. || date>0x31 )
  331. date=0x01;
  332. if((date & 0x0f)>0x09)
  333. {date +=0x10;
  334. date &=0xf0;
  335. }
  336. ds1302_Write(write_date,date);
  337. date = ds1302_Read(read_date);
  338. update_disbuf(); //更新显示字符
  339. while(!(P2IN & BIT7))
  340. display();
  341. break;
  342. case 4: //此时处理全局变量day
  343. n++;
  344. if(n>0x07)
  345. n=1;
  346. ds1302_Write(write_day,n);
  347. n = ds1302_Read(read_day);
  348. update_disbuf(); //更新显示字符
  349. while(!(P2IN & BIT7))
  350. display();
  351. break;
  352. case 5: //此时处理全局变量hour
  353. hour++;
  354. if(hour>0x23)
  355. hour=0;
  356. if((hour & 0x0f)>0x09)
  357. {hour +=0x10;
  358. hour &=0xf0;
  359. }
  360. ds1302_Write(write_hour,hour);
  361. hour = ds1302_Read(read_hour);
  362. update_disbuf(); //更新显示字符
  363. while(!(P2IN & BIT7))
  364. display();
  365. break;
  366. case 6: //此时处理全局变量minute
  367. minute++;
  368. if(minute>0x59)
  369. minute=0;
  370. if((minute & 0x0f)>0x09)
  371. {minute +=0x10;
  372. minute &=0xf0;
  373. }
  374. ds1302_Write(write_minute,minute);
  375. minute = ds1302_Read(read_minute);
  376. update_disbuf(); //更新显示字符
  377. while(!(P2IN & BIT7))
  378. display();
  379. break;
  380. case 7: //此时处理全局变量second
  381. second++;
  382. if(second>0x59)
  383. second=0;
  384. if((second & 0x0f)>0x09)
  385. {second +=0x10;
  386. second &=0xf0;
  387. }
  388. ds1302_Write(write_second,second);
  389. second = ds1302_Read(read_second);
  390. update_disbuf(); //更新显示字符
  391. while(!(P2IN & BIT7))
  392. display();
  393. break;
  394. default: break;
  395. }
  396. }
  397. ds1302_Write(write_protect,0x80);//打开写保护
  398. }
  399. }
  400. //纪念日处理程序
  401. void jww(void)
  402. {char ww_xx;
  403. for(ww_xx=0;ww_xx<16;ww_xx++)
  404. {
  405. dis_buf1[ww_xx] = love1[ww_xx];
  406. dis_buf2[ww_xx] = love2[ww_xx];
  407. }
  408. love_years= year - 0x11; //减去2011年
  409. dis_buf2[8]=love_years/16 + 0x30;
  410. dis_buf2[9]=love_years%16 + 0x30;
  411. display();
  412. _DINT();
  413. __delay_cycles(2000000); //延时显示出来
  414. _EINT();
  415. }
  416. //主函数
  417. void main (void)
  418. {
  419. CSL_init(); // 初始化单片机
  420. lsd1602_init(); // 初始化LCD1602
  421. ds1302_init(); //初始化DS1302
  422. while(1)
  423. {
  424. _DINT();
  425. data_pro(); //读取并处理数据
  426. _EINT();
  427. if(month== 0x03 && date== 0x07)//3月7日纪念日
  428. jww();
  429. update_disbuf(); //更新显示字符
  430. display(); //显示时间
  431. if(month== 0x03 && date== 0x07)//3月7日纪念日
  432. __delay_cycles(1000000);
  433. }
  434. }


本帖子中包含更多资源

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

×
luhshuay 发表于 2015-1-24 10:33 | 显示全部楼层
爱情万年历,版主很有创意啊,呵呵。支持下
 楼主| dirtwillfly 发表于 2015-1-24 20:07 | 显示全部楼层
luhshuay 发表于 2015-1-24 10:33
爱情万年历,版主很有创意啊,呵呵。支持下

:L不是我的创意
acer4736 发表于 2015-1-26 07:50 | 显示全部楼层
好炫酷的题目
jinpaidianzi 发表于 2015-1-26 07:53 | 显示全部楼层
不知道实用不实用 呵呵
teabottle 发表于 2015-1-26 07:59 | 显示全部楼层
适合谈恋爱的朋友呦
wangjinlili 发表于 2015-1-26 08:01 | 显示全部楼层
当年谈恋爱的时候怎么没有这个呢
meishizhaoshi 发表于 2015-1-26 08:08 | 显示全部楼层
很不错 软硬件都有了
shibalihuandao 发表于 2015-1-26 08:12 | 显示全部楼层
感觉这个题目起的好抢镜啊 哈哈
sishangcine 发表于 2015-1-26 08:16 | 显示全部楼层
可以学习学习
heibaiyinjiag 发表于 2015-1-26 08:19 | 显示全部楼层
好博人眼球啊 哈哈
smilingangel 发表于 2015-1-26 21:13 | 显示全部楼层
这个最主要的就是做好RTC部分的啊,时间日期的全靠着了。
1988020566 发表于 2015-1-30 00:01 | 显示全部楼层
代码太长了
112207301219 发表于 2015-5-12 15:12 | 显示全部楼层
没有成品效果图,有点遗憾。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:欢迎进入TI MCU论坛      21ic TI技术交流1群:61549143(已满),  21ic TI技术交流2群:311421422 我的博客:http://blog.timcu.com/

1199

主题

35121

帖子

1122

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