[原创] 【TI首届低功耗设计大赛】之电子产品运行数据记录仪

littleshrimp   2014-12-28 21:15 楼主
【TI首届低功耗设计大赛】 之电子产品运行数据记录仪
在研发电子产品的过程中可能会遇到自己设计的产品运行不稳定,经过出现异常现象,查看代码又发现不了问题。这时候一搬会弄一台笔记本,把串口连接到新产品上,记录新产品运行时的日志。这种方法对测试环境有一定的局限性,比如强干扰的环境、空间受限的环境、室外环境等,如果需要长时间记录,笔记本还需要配备电源,在没无法提供电源接入的场合笔记本就无法胜任此工作。
另外笔记本的测试成本过高,在多个产品同时测试时提供大量的笔记本也是不现实滴。
本方案是利用MSP430FR5969优越性能,通过一条串口线接收新产品的日志数据,实时保存到FRAM中,虽然新产品测试时的日志文件很大,但通常我们更关心的是出故障时的一段数据,通过反复重写保留最新日志数据。MSP430FR5969不仅功耗低而且写入速度也非常快,所以可以使用一个小小的钮扣电池来提供电能。这样记录仪的体积会变的很小,非常适用一些空间受限的场合。
今天一整天都在赶活动,快饿死了,废话不说,上代码:
  1. #include <stdint.h>
  2. #include <string.h>
  3. #include <msp430.h>
  4. #include "mcu_config.h"
  5. #include "hal_timer.h"
  6. #define FRAM_STORE_START_ADDRESS 0xD000 //数据存储起始地址
  7. #define OFFSET_LEN 4 //offset自身的长度(字节)
  8. #define MAX_STORE_LEN 10000 //最大存储深度
  9. #define BUFFER_LEN 128
  10. uint32_t *FRAM_offset_write_ptr; //写入偏移量的指针
  11. char *FRAM_str_write_ptr; //写入字符串的指针
  12. uint8_t str_counter = 0; //存储数据计数器
  13. uint8_t clear_frame_command[] = "clear fram";
  14. uint8_t print_frame_command[] = "print fram";
  15. uint8_t buf[BUFFER_LEN];
  16. uint8_t buf_index = 0;
  17. uint32_t fram_read_offset(void)
  18. {
  19. uint32_t fram_store_address_offset; //数据偏移地址,保留4个字节用来存储修改后的偏移地址
  20. FRAM_offset_write_ptr = (uint32_t *)(FRAM_STORE_START_ADDRESS); //初始化读取fram_store_address_offset 的地址
  21. fram_store_address_offset = *FRAM_offset_write_ptr;
  22. if(fram_store_address_offset == 0xffffffff) //第一次上电
  23. {
  24. fram_store_address_offset = OFFSET_LEN;
  25. }
  26. return fram_store_address_offset;
  27. }
  28. void fram_write_offset(uint32_t offset)
  29. {
  30. FRAM_offset_write_ptr = (uint32_t *)(FRAM_STORE_START_ADDRESS); //初始化读取fram_store_address_offset 的地址
  31. *FRAM_offset_write_ptr = offset;
  32. }
  33. void fram_write_byte(uint8_t c)
  34. {
  35. uint32_t offset = fram_read_offset();
  36. FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS + offset ); //初始化数据存储地址
  37. *FRAM_str_write_ptr++ = c; //将数据写入FRAM
  38. if(offset++ > MAX_STORE_LEN)
  39. {
  40. offset = OFFSET_LEN; //从零开始记录
  41. } //更新指针偏移
  42. fram_write_offset(offset);
  43. }
  44. void fram_write_n_byte(uint8_t *buf,uint16_t len)
  45. {
  46. uint16_t i;
  47. for(i=0;i<len;i++)
  48. {
  49. fram_write_byte(buf[i]);
  50. }
  51. }
  52. void fram_write_char(char c)
  53. {
  54. fram_write_byte((uint8_t)c);
  55. }
  56. void fram_write_str(char * str)
  57. {
  58. uint16_t len = strlen(str);
  59. uint32_t offset = fram_read_offset();
  60. FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS + offset ); //初始化数据存储地址
  61. while(*str)
  62. {
  63. *FRAM_str_write_ptr++ = *str++; //将数据写入FRAM
  64. }
  65. offset += len; //更新指针偏移
  66. fram_write_offset(offset);
  67. }
  68. void uart_init(void)
  69. {
  70. // Configure GPIO
  71. P1OUT &= ~BIT0; // Clear P1.0 output latch
  72. P1DIR |= BIT0; // For LED on P1.0
  73. P2SEL1 |= BIT0 | BIT1; // USCI_A0 UART operation
  74. P2SEL0 &= ~(BIT0 | BIT1);
  75. // Configure USCI_A0 for UART mode
  76. UCA0CTLW0 = UCSWRST; // Put eUSCI in reset
  77. UCA0CTL1 |= UCSSEL__SMCLK; // CLK = SMCLK
  78. UCA0BR0 = 8; // 1000000/115200 = 8.68
  79. UCA0MCTLW = 0xD600; // 1000000/115200 - INT(1000000/115200)=0.68
  80. // UCBRSx value = 0xD6 (See UG)
  81. UCA0BR1 = 0;
  82. UCA0CTL1 &= ~UCSWRST; // release from reset
  83. UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
  84. }
  85. void uart_tx_byte(uint8_t b)
  86. {
  87. while(!(UCA0IFG & UCTXIFG));
  88. UCA0TXBUF = b; // Load data onto buffer
  89. }
  90. void uart_tx_n_bytes(uint8_t *buf,uint16_t len)
  91. {
  92. uint16_t i;
  93. for(i=0;i<len;i++)
  94. {
  95. uart_tx_byte(buf[i]);
  96. }
  97. }
  98. void uart_tx_str(char * str)
  99. {
  100. while(*str)
  101. {
  102. uart_tx_byte(*str++);
  103. }
  104. }
  105. void fram_clear(void)
  106. {
  107. uint32_t i;
  108. uint32_t offset = fram_read_offset();
  109. //FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS); //初始化数据存储地址
  110. for(i=0;i<MAX_STORE_LEN;i++)
  111. {
  112. if(i%128 == 0)
  113. {
  114. FRAM_str_write_ptr = (char *)(FRAM_STORE_START_ADDRESS + i); //初始化数据存储地址
  115. }
  116. *FRAM_str_write_ptr++ = 0xff;
  117. }
  118. uart_tx_str("done");
  119. //将数据写入FRAM
  120. }
  121. void print_all_str(void)
  122. {
  123. uint32_t i;
  124. uint32_t len = fram_read_offset(); //获得存储的数据长度
  125. uint8_t * start_ptr = (uint8_t *)(FRAM_STORE_START_ADDRESS + OFFSET_LEN);
  126. for(i=0;i<len;i++)
  127. {
  128. uart_tx_byte(*start_ptr++);
  129. }
  130. }
  131. uint8_t compare(uint8_t * a,uint8_t *b,uint8_t len)
  132. {
  133. uint8_t i;
  134. for(i=0;i< len;i++)
  135. {
  136. if(a[i] != b[i])
  137. {
  138. return 0;
  139. }
  140. }
  141. return 1;
  142. }
  143. int main(void)
  144. {
  145. uint16_t i;
  146. WDTCTL = WDTPW | WDTHOLD; // Stop watchdog
  147. // Configure GPIO
  148. PJOUT &= ~BIT0; // Clear P1.0 output latch
  149. PJDIR |= BIT0; // For LED on P1.0
  150. PM5CTL0 &= ~LOCKLPM5;
  151. __delay_cycles(65500);
  152. // fram_write("hello eeworld!\n");
  153. // fram_write("msp430fr5969!\n");
  154. uart_init();
  155. print_all_str();
  156. while(1)
  157. {
  158. __bis_SR_register(LPM0_bits | GIE); // Enter LPM0, interrupts enabled
  159. if(compare(buf,clear_frame_command,strlen(clear_frame_command)))
  160. {
  161. fram_clear();
  162. buf_index = 0;
  163. }
  164. else if(compare(buf,print_frame_command,strlen(print_frame_command)))
  165. {
  166. print_all_str();
  167. buf_index = 0;
  168. }
  169. else
  170. {
  171. fram_write_n_byte(buf,buf_index);
  172. buf_index = 0;
  173. }
  174. }
  175. }
  176. #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
  177. #pragma vector=USCI_A0_VECTOR
  178. __interrupt void USCI_A0_ISR(void)
  179. #elif defined(__GNUC__)
  180. void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
  181. #else
  182. #error Compiler not supported!
  183. #endif
  184. {
  185. switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
  186. {
  187. case USCI_NONE: break;
  188. case USCI_UART_UCRXIFG:
  189. buf[buf_index] = UCA0RXBUF;
  190. UCA0TXBUF = buf[buf_index];
  191. if(buf[buf_index] == '\n')
  192. {
  193. __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti
  194. }
  195. buf_index++;
  196. break;
  197. case USCI_UART_UCTXIFG: break;
  198. case USCI_UART_UCSTTIFG: break;
  199. case USCI_UART_UCTXCPTIFG: break;
  200. }
  201. }
视频讲解
本帖最后由 littleshrimp 于 2014-12-29 08:31 编辑
虾扯蛋,蛋扯虾,虾扯蛋扯虾

回复评论 (4)

用SD卡不是更好?
点赞  2014-12-31 10:06

#include "mcu_config.h"

#include "hal_timer.h"

请问这两个头文件哪里可以下载呢?

点赞  2020-10-26 22:37
引用: asd1005823780 发表于 2020-10-26 22:37 #include "mcu_config.h" #include "hal_timer.h" 请问这两个头文件哪里可以下载呢? ...

原来的工程找不到了,这是其它地方搜到的,你可以参考一下。

mcu_config.h (4.82 KB)
(下载次数: 8, 2020-10-27 11:37 上传)


hal_timer.h (1.62 KB)
(下载次数: 5, 2020-10-27 11:37 上传)


hal_timer.c (5.78 KB)
(下载次数: 4, 2020-10-27 11:37 上传)


 

虾扯蛋,蛋扯虾,虾扯蛋扯虾
点赞  2020-10-27 11:37
引用: littleshrimp 发表于 2020-10-27 11:37 原来的工程找不到了,这是其它地方搜到的,你可以参考一下。  

好的,感谢!

点赞  2020-11-7 14:43
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复