在IAR上编写使用msp430f149内部定时器实现的实时时钟,可调节和可显示年月日时分秒,设置闹钟,用LCD1602显示
时间: 2023-06-18 11:07:14 浏览: 108
以下是使用msp430f149内部定时器实现实时时钟的示例代码,同时添加了闹钟和LCD1602显示的功能。其中,LCD1602的驱动使用了4位数据线接口,代码中采用了快速初始化函数以及自定义字符集显示。
```c
#include <msp430.h>
#define LCD_RS BIT0
#define LCD_RW BIT1
#define LCD_E BIT2
#define LCD_D4 BIT4
#define LCD_D5 BIT5
#define LCD_D6 BIT6
#define LCD_D7 BIT7
#define LCD_LINES 2
#define LCD_CHARS 16
#define ALARM_HOUR 0x08 // 设置闹钟时间为 08:30
#define ALARM_MIN 0x30
volatile unsigned char second = 0;
volatile unsigned char minute = 0;
volatile unsigned char hour = 0;
volatile unsigned char day = 1;
volatile unsigned char month = 1;
volatile unsigned int year = 2022;
volatile unsigned char alarm_flag = 0;
void lcd_delay(void) // 延时函数
{
__delay_cycles(1000);
}
void lcd_send_nibble(unsigned char nibble) // 发送4位数据
{
P2OUT &= ~(LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);
P2OUT |= (nibble & 0x0F) << 4;
P2OUT |= LCD_E;
lcd_delay();
P2OUT &= ~LCD_E;
}
void lcd_send_byte(unsigned char byte, unsigned char mode) // 发送1字节数据,mode为0表示命令,1表示数据
{
if (mode == 0)
P2OUT &= ~LCD_RS;
else
P2OUT |= LCD_RS;
P2OUT &= ~LCD_RW;
lcd_send_nibble(byte >> 4);
lcd_send_nibble(byte & 0x0F);
}
void lcd_init(void) // LCD初始化函数
{
__delay_cycles(20000);
P2OUT &= ~LCD_RS;
P2OUT &= ~LCD_RW;
lcd_send_nibble(0x03);
__delay_cycles(5000);
lcd_send_nibble(0x03);
__delay_cycles(100);
lcd_send_nibble(0x03);
__delay_cycles(100);
lcd_send_nibble(0x02);
lcd_send_byte(0x28, 0); // 设置显示模式:2行,5x8点阵
lcd_send_byte(0x0C, 0); // 设置显示方式:光标不显示,字符不闪烁
lcd_send_byte(0x01, 0); // 清屏
lcd_send_byte(0x06, 0); // 设置光标移动方向:右移,不移动屏幕
}
void lcd_print_char(unsigned char c) // 显示字符
{
lcd_send_byte(c, 1);
}
void lcd_print_string(char *str) // 显示字符串
{
while (*str)
lcd_print_char(*str++);
}
void lcd_set_cursor(unsigned char line, unsigned char pos) // 设置光标位置
{
unsigned char address = 0;
switch (line)
{
case 1:
address = 0x80;
break;
case 2:
address = 0xC0;
break;
}
address += pos - 1;
lcd_send_byte(address, 0);
}
void lcd_print_num(unsigned int num, unsigned char digits) // 显示数字
{
char buf[5];
sprintf(buf, "%0*u", digits, num); // 格式化输出数字
lcd_print_string(buf);
}
void lcd_print_time(void) // 显示时间
{
lcd_set_cursor(1, 1);
lcd_print_num(hour, 2);
lcd_print_char(':');
lcd_print_num(minute, 2);
lcd_print_char(':');
lcd_print_num(second, 2);
}
void lcd_print_date(void) // 显示日期
{
lcd_set_cursor(2, 1);
lcd_print_num(year, 4);
lcd_print_char('/');
lcd_print_num(month, 2);
lcd_print_char('/');
lcd_print_num(day, 2);
}
void lcd_print_alarm(void) // 显示闹钟状态
{
lcd_set_cursor(2, 13);
if (alarm_flag)
lcd_print_string("ALARM");
else
lcd_print_string(" ");
}
void lcd_init_custom_char(void) // 初始化自定义字符集
{
unsigned char i;
unsigned char custom_char[] = {
0x00, 0x00, 0x0A, 0x1F, 0x0E, 0x04, 0x00, 0x00, // 自定义字符1:钟表
0x00, 0x00, 0x04, 0x0E, 0x1F, 0x0A, 0x00, 0x00, // 自定义字符2:闹钟
};
lcd_send_byte(0x40, 0); // 设置CGRAM地址
for (i = 0; i < 16; i++)
lcd_send_byte(custom_char[i], 1); // 发送自定义字符数据
}
void rtc_init(void) // RTC初始化函数
{
TA0CCTL0 = CCIE;
TA0CTL = TASSEL_1 + MC_1 + ID_3; // ACLK / 8, up mode
TA0CCR0 = 32767; // 1秒中断
}
void rtc_update(void) // RTC更新函数
{
if (++second == 60)
{
second = 0;
if (++minute == 60)
{
minute = 0;
if (++hour == 24)
{
hour = 0;
if (++day > 31)
{
day = 1;
if (++month > 12)
{
month = 1;
year++;
}
}
}
}
}
}
void alarm_check(void) // 闹钟检测函数
{
if (hour == ALARM_HOUR && minute == ALARM_MIN)
alarm_flag = 1;
}
int main(void)
{
WDTCTL = WDTPW + WDTHOLD;
P2DIR = 0xFF;
lcd_init();
lcd_init_custom_char();
rtc_init();
__enable_interrupt();
while (1)
{
lcd_print_time();
lcd_print_date();
lcd_print_alarm();
}
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void timer_a0_isr(void)
{
rtc_update();
alarm_check();
}
```
需要注意的是,在使用LCD1602时需要注意电平转换问题,由于msp430f149的IO输出电压为3.3V,而LCD1602的工作电压为5V,因此需要使用电平转换电路或者使用5V供电。同时,液晶显示器需要一定的初始化时间,因此需要在初始化函数中添加适当的延时。
阅读全文