8月14_day10_IO流扩展

1. 缓冲流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrTPpD56-1628948845358)(C:\Users\14324\AppData\Roaming\Typora\typora-user-images\image-20210814184050529.png)]

1.1 缓冲流概述

缓冲流自带缓冲区,可以提高原始字节流、字符流读写数据的性能

1.2 字节缓冲流

BufferedInputStream

BufferedOutputStream

构造器说明
public BufferedInputStream(InputStream is)可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道
public BufferedOutputStream(OutputStream os)可以把低级的字节输出流包装成一个高级的缓冲字节输出流管道

1.2.1 字节缓冲流的性能分析

字节缓冲输入流和输出流自带了8kb的缓冲池

建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式

1.2.2 用缓冲流字节数组复制

public static void main(String[] args) throws IOException {
	//创建
    File file = new File("Test08_14\\src\\data2.txt");
    //创建低级的字节输入流
    FileInputStream fis = new FileInputStream(file);
    //创建字节输入缓冲流
    BufferedInputStream bis = new BufferedInputStream(fis);
	//创建
    File file1  =new File("Test08_14\\src\\data1.txt");
    //创建低级的字节输出流
    FileOutputStream fos = new FileOutputStream(file1);
    //创建字节输出缓冲流
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    //定义数组  
    byte[] buffer = new byte[1024];
    int len;
	//循环输出
    while ((len = bis.read(buffer))!=-1 ) {
        bos.write(buffer,0,len);
    }
    //关闭流
    bis.close();
    bos.close();
}

1.3 字符缓冲流

​ 字符缓冲流自带8K缓冲区

1.3.1 字符缓冲流的构造器

BufferedReader

构造器说明
public BufferedReader(Reader r)可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道

BufferedWriter

构造器说明
public BufferedWriter(Writer w)可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道

1.3.2 字符缓冲流的特有方法

​ **输入流: **

方法说明
public String readLine()读取一行数据返回,如果读取没有完毕,无行可读返回null

​ **输出流: **

方法说明
public void newLine()换行操作

1.3.3 用缓冲流字符复制

public static void main(String[] args) throws IOException {
    //创建
    File file = new File("Test08_14\\src\\data2.txt");
    //创建低级的字符输入流
    FileReader fr = new FileReader(file);
    //创建字符输入缓存流
    BufferedReader br = new BufferedReader(fr);
    //创建
    File file1  =new File("Test08_14\\src\\data1.txt");
    //创建低级的字符输出流
    FileWriter fw = new FileWriter(file1);
    //创建字符输出缓存流
    BufferedWriter bw = new BufferedWriter(fw);
    String s;
    while ((s = br.readLine()) != null) {
        //写入数据
        bw.write(s);
        //换行
        bw.newLine();
    }
    //释放流
    bw.close();
    br.close();
}

2. 转换流__字符流

先通过字节流得到字节数据,通过转换流转换为指定的字符流

字符流再通过指定的编码模式转为字节流进行写入

2.1 字符输入转换流

​ **字符输入转换流:**InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流。

构造器说明
public InputStreamReader(InputStream is)可以把原始的字节流按照代码默认编码转换成字符输入流
public InputStreamReader(InputStream is ,String charset)可以把原始的字节流按照指定编码转换成字符输入流

2.2 字符输出转换流

​ **字符输入转换流:**OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流。

构造器说明
public OutputStreamWriter(OutputStream os)可以把原始的字节输出流按照代码默认编码转换成字符输出流。
public OutputStreamWriter(OutputStream os,String charset)可以把原始的字节输出流按照指定编码转换成字符输出流(重点)

2.3 用字符转换流进行复制

public static void main(String[] args) throws IOException {
    //创建
    File file = new File("Test08_14\\src\\data2.txt");
    //创建低级字节输入流,获取文件的字节流
    FileInputStream fis = new FileInputStream(file);
    //创建字符转换流,可以将字节以指定的编码模式存储为字节流
    InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
    //创建字节输入缓冲流
    BufferedReader br = new BufferedReader(isr);

	//创建
    File file1  =new File("Test08_14\\src\\data1.txt");
    //创建低级字节输出流
    FileOutputStream fos = new FileOutputStream(file1);
    //创建字符转换流,可以将字节流以指定的编码模式转为字符流
    OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
    //创建字符输出缓存流
    BufferedWriter bw = new BufferedWriter(osw);

    String s;
    while ((s = br.readLine()) != null) {
        bw.write(s);
        bw.newLine();
    }
    bw.close();
    br.close();
}

3. 序列化

​ 对象序列化必须实现序列化接口 Serializable

3.1 对象序列化

**作用:**以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化。

**对象字节输出流:**ObjectOutputStream

构造器说明
public ObjectOutputStream(OutputStream out)把低级字节输出流包装成高级的对象字节输出流

序列化方法:

方法名称说明
public final void writeObject(Object obj)把对象写出去到对象序列化流的文件中去
public static void main(String[] args) throws IOException {
    //创建字节输出流
    FileOutputStream fos = new FileOutputStream("Test08_14\\src\\data3.txt");
    //创建对象字节输出流
    ObjectOutputStream objectout = new ObjectOutputStream(fos);
    //创建对象
    Student s = new Student("name",18);
    //调用特有方法writeObject  将对象写入文件
    objectout.writeObject(s);
    //关闭流
    objectout.close();
}

3.2 对象反序列化

作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象

对象字节输入流:ObjectInputStream

构造器说明
public ObjectInputStream(InputStream out)把低级字节输如流包装成高级的对象字节输入流

反序列化方法:

方法名称说明
public Object readObject()把存储到磁盘文件中去的对象数据恢复成内存中的对象返回
public static void main(String[] args) throws Exception {
    //创建字节输入流
    FileInputStream fis = new FileInputStream("Test08_14\\src\\data3.txt");
    //创建对象字节输入流
    ObjectInputStream ois = new ObjectInputStream(fis);
    //创建学生对象,用来接调用readObject()方法返回的student对象
    Student s =(Student) ois.readObject();
    //输出查看student对象
    System.out.println(s);
}

4.打印流

作用:打印流可以实现方便、高效的打印数据到文件中去。

PrintStream,PrintWriter两个类

4.1 构造器及方法

PrintStream构造器

构造器说明
public PrintStream(OutputStream os)打印流直接通向字节输出流管道
public PrintStream(File f)打印流直接通向文件对象
public PrintStream(String filepath)打印流直接通向文件路径

方法

方法说明
public void print(Xxx xx)打印任意类型的数据出去

PrintWrite构造器

构造器说明
public PrintWriter(OutputStream os)打印流直接通向字节输出流管道
public PrintWriter (Writer w)打印流直接通向字符输出流管道
public PrintWriter (File f)打印流直接通向文件对象
public PrintWriter (String filepath)打印流直接通向文件路径

方法

方法说明
public void print(Xxx xx)打印任意类型的数据出去

4.2 PrintStream和PrintWriter的区别

打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)

PrintStream继承自字节输出流OutputStream,支持写字节数据的方法。

PrintWriter继承自字符输出流Writer,支持写字符数据出去。

public static void main(String[] args) throws Exception {
    // 1、创建一个打印流对象
    //PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt" , true)); 
    // 追加数据,在低级管道后面加True
    //PrintStream ps = new PrintStream("io-app2/src/ps.txt" );
    PrintWriter ps = new PrintWriter("io-app2/src/ps.txt"); 
    // 打印功能上与PrintStream的使用没有区别

    ps.println(97);
    ps.println('a');
    ps.println(23.3);
    ps.println(true);
    ps.println("我是打印流输出的,我是啥就打印啥");

    ps.close();
}

4.3 输出语句的重定向

​ 作用:了解改变输出语句的位置到文件

public static void main(String[] args) throws Exception {
    System.out.println("锦瑟无端五十弦");
    System.out.println("一弦一柱思华年");

    // 改变输出语句的位置(重定向)
    PrintStream ps = new PrintStream("io-app2/src/log.txt");
    System.setOut(ps); // 把系统打印流改成我们自己的打印流

    System.out.println("庄生晓梦迷蝴蝶");
    System.out.println("望帝春心托杜鹃");
}

5. Properties属性集对象

​ Properties代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去。
​ 属性文件:后缀是.properties结尾的文件,里面的内容都是 key=value,后续做系统配置信息的。

Properties和IO流结合的方法:

主要是用store() 方法和 load()方法

构造器说明
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
void load(Reader reader)从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流
public Object setProperty(String key, String value)保存键值对(put)
public String getProperty(String key)使用此属性列表中指定的键搜索属性值 (get)
public Set stringPropertyNames()所有键的名称的集合 (keySet())

Properties的作用?
可以存储Properties属性集的键值对数据到属性文件中去:void store(Writer writer, String comments)

可以加载属性文件中的数据到Properties对象中来:void load(Reader reader)

写数据

public static void main(String[] args) throws IOException {
    Properties properties = new Properties();
    properties.setProperty("admin", "123456");
    properties.setProperty("dlei", "003197");
    properties.setProperty("heima", "itcast");
    System.out.println(properties);
    /*
      参数一:保存管道 字符输出流管道
      参数二:保存心得
      */
    properties.store(new FileWriter("Test08_14/src/data444.txt")
                     , "this is 1!");
}

读数据

public static void main(String[] args) throws IOException {
    // 需求:Properties读取属性文件中的键值对信息。(读取)
    Properties properties = new Properties();

    // 加载属性文件中的键值对数据到属性对象properties中去
    properties.load(new FileReader("Test08_14/src/data444.txt"));

    System.out.println(properties);
    String rs = properties.getProperty("dlei");
    System.out.println(rs);
    properties.setProperty("admin","123wwwwwwwww");
    System.out.println(properties);

}

6 IO框架

FileUtils主要有如下方法:

方法名说明
String readFileToString(File file, String encoding)读取文件中的数据, 返回字符串
void copyFile(File srcFile, File destFile)复制文件。
void copyDirectoryToDirectory(File srcDir, File destDir)复制文件夹。

步骤

  • 在项目中创建一个文件夹:lib
  • 将commons-io-2.6.jar文件复制到lib文件夹
  • 在jar文件上点右键,选择 Add as Library -> 点击OK
  • 在类中导包使用
 public static void main(String[] args) throws Exception {
        // 1.完成文件复制!
        IOUtils.copy(new FileInputStream("D:\\resources\\hushui.jpeg"),
                new FileOutputStream("D:\\resources\\hushui2.jpeg"));

        // 2.完成文件复制到某个文件夹下!
        FileUtils.copyFileToDirectory(new File("D:\\resources\\hushui.jpeg"), new File("D:/"));

          // 3.完成文件夹复制到某个文件夹下!
          FileUtils.copyDirectoryToDirectory(new File("D:\\resources") , new File("D:\\new"));
           FileUtils.deleteDirectory(new File("D:\\new"));

        FileUtils.deleteDirectory(new File("D:\\new"));
    }
源码来自:https://pan.quark.cn/s/41b9d28f0d6d 在信息技术领域中,jQuery作为一个广受欢迎的JavaScript框架,显著简化了诸多操作,包括对HTML文档的遍历、事件的管理、动画的设计以及Ajax通信等。 本篇文档将深入阐释如何运用jQuery达成一个图片自动播放的功能,这种效果常用于网站的轮播展示或幻灯片演示,有助于优化用户与页面的互动,使网页呈现更加动态的视觉体验。 为了有效实施这一功能,首先需掌握jQuery的核心操作。 通过$符号作为接口,jQuery能够迅速选取DOM组件,例如$("#id")用于选取具有特定ID的元素,而$(".class")则能选取所有应用了某类class的元素。 在选定元素之后,可以执行多种行为,诸如事件监听、样式的变更、内容的更新以及动画的制作等。 关于“一个基于jQuery的图片自动播放功能”,首要任务是准备一组图片素材,这些素材将被整合至一个容器元素之中。 例如,可以构建一个div元素,将其宽度设定为单张图片的尺寸,再借助CSS实现溢出内容的隐藏,从而构建出水平滚动的初始框架。 ```html<div id="slider"> <img src="image1.jpg" alt="Image 1"> <img src="image2.jpg" alt="Image 2"> <!-- 更多图片内容... --></div>```接着,需要编写jQuery脚本以实现图片的自动切换。 这通常涉及到定时器的运用,以设定周期性间隔自动更换当前显示的图片。 通过使用`.fadeOut()`和`.fadeIn()`方法,能够实现图片间的平滑过渡,增强视觉效果。 ```javascript$(document).re...
#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <avr/eeprom.h> #include <string.h> #define delay_ms(x) _delay_ms(x) // LCD 相关引脚定义 #define LCD_RS PC0 #define LCD_RW PC1 #define LCD_E PC2 #define LCD_D4 PA4 #define LCD_D5 PA5 #define LCD_D6 PA6 #define LCD_D7 PA7 // 按键引脚定义(使用PORTD) #define SET_BUTTON PIND0 #define ADD_BUTTON PIND1 #define SUB_BUTTON PIND2 // LED 引脚定义 #define LED_PIN PB3 // EEPROM存储地址 #define EEPROM_TIME_HOUR_ADDR 0x00 #define EEPROM_TIME_MINUTE_ADDR 0x01 #define EEPROM_DATE_YEAR_ADDR 0x02 #define EEPROM_DATE_MONTH_ADDR 0x03 #define EEPROM_DATE_DAY_ADDR 0x04 // 全局变量 volatile uint8_t hour = 12; // 小时(0-23) volatile uint8_t minute = 0; // 分钟(0-59) volatile uint8_t second = 0; // 秒(0-59) volatile uint8_t year = 23; // 年份(后两位) volatile uint8_t month = 1; // 月份(1-12) volatile uint8_t day = 1; // 日期(1-31) volatile uint8_t set_mode = 0; // 0:正常显示, 1:设置小时, 2:设置分钟, 3:设置年, 4:设置月, 5:设置日 volatile uint8_t blink_state = 0; // 闪烁状态 volatile uint8_t timer1_counter = 0; // 定时器计数器 // 闹钟结构 typedef struct { uint8_t hour; uint8_t minute; uint8_t enabled; } Alarm; Alarm alarm1 = {8, 0, 0}; // 闹钟1,默认8:00,关闭 Alarm alarm2 = {12, 0, 0}; // 闹钟2,默认12:00,关闭 // LCD初始化 void LCD_Init() { // 设置数据端口为输出 DDRA |= (1<<LCD_D4) | (1<<LCD_D5) | (1<<LCD_D6) | (1<<LCD_D7); // 设置控制端口为输出 DDRC |= (1<<LCD_RS) | (1<<LCD_RW) | (1<<LCD_E); // 初始化序列 delay_ms(50); // 等待LCD上电稳定 // 4位模式初始化 LCD_Write_Command(0x33); LCD_Write_Command(0x32); LCD_Write_Command(0x28); // 4位模式,2行显示,5x8点阵 LCD_Write_Command(0x0C); // 显示开,光标关,闪烁关 LCD_Write_Command(0x06); // 增量模式,不移位 LCD_Write_Command(0x01); // 清屏 delay_ms(2); } // 向LCD发送命令 void LCD_Write_Command(unsigned char cmd) { PORTC &= ~(1<<LCD_RS); // RS=0 命令模式 PORTC &= ~(1<<LCD_RW); // RW=0 写入 // 发送高4位 PORTA = (PORTA & 0x0F) | (cmd & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 // 发送低4位 PORTA = (PORTA & 0x0F) | ((cmd << 4) & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 delay_ms(1); } // 向LCD发送数据 void LCD_Write_Data(unsigned char data) { PORTC |= (1<<LCD_RS); // RS=1 数据模式 PORTC &= ~(1<<LCD_RW); // RW=0 写入 // 发送高4位 PORTA = (PORTA & 0x0F) | (data & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 // 发送低4位 PORTA = (PORTA & 0x0F) | ((data << 4) & 0xF0); PORTC |= (1<<LCD_E); // E=1 delay_ms(1); PORTC &= ~(1<<LCD_E); // E=0 delay_ms(1); } // 在LCD上显示字符串 void LCD_Display_String(char *str) { while (*str) { LCD_Write_Data(*str++); } } // 设置LCD光标位置 void LCD_Set_Cursor(uint8_t row, uint8_t col) { uint8_t address; if (row == 0) { address = 0x80 + col; } else { address = 0xC0 + col; } LCD_Write_Command(address); } // 显示时间 void Display_Time() { char buffer[16]; // 第一行显示时间 LCD_Set_Cursor(0, 4); sprintf(buffer, "%02d:%02d:%02d", hour, minute, second); LCD_Display_String(buffer); // 第二行显示日期 LCD_Set_Cursor(1, 4); sprintf(buffer, "20%02d-%02d-%02d", year, month, day); LCD_Display_String(buffer); } // 显示设置模式 void Display_Set_Mode() { char buffer[16]; LCD_Set_Cursor(0, 0); LCD_Display_String("Set:"); switch(set_mode) { case 1: // 设置小时 if(blink_state) { sprintf(buffer, "Hour: %02d", hour); } else { sprintf(buffer, "Hour: "); } break; case 2: // 设置分钟 if(blink_state) { sprintf(buffer, "Minute:%02d", minute); } else { sprintf(buffer, "Minute: "); } break; case 3: // 设置年 if(blink_state) { sprintf(buffer, "Year: 20%02d", year); } else { sprintf(buffer, "Year: "); } break; case 4: // 设置月 if(blink_state) { sprintf(buffer, "Month: %02d", month); } else { sprintf(buffer, "Month: "); } break; case 5: // 设置日 if(blink_state) { sprintf(buffer, "Day: %02d", day); } else { sprintf(buffer, "Day: "); } break; default: sprintf(buffer, "Normal Mode "); } LCD_Set_Cursor(0, 5); LCD_Display_String(buffer); // 仍然显示时间日期 LCD_Set_Cursor(1, 0); sprintf(buffer, "Time:%02d:%02d:%02d", hour, minute, second); LCD_Display_String(buffer); } // 从EEPROM加载时间日期 void Load_Time_From_EEPROM() { hour = eeprom_read_byte((uint8_t*)EEPROM_TIME_HOUR_ADDR); minute = eeprom_read_byte((uint8_t*)EEPROM_TIME_MINUTE_ADDR); year = eeprom_read_byte((uint8_t*)EEPROM_DATE_YEAR_ADDR); month = eeprom_read_byte((uint8_t*)EEPROM_DATE_MONTH_ADDR); day = eeprom_read_byte((uint8_t*)EEPROM_DATE_DAY_ADDR); // 检查读取的值是否有效 if(hour > 23) hour = 0; if(minute > 59) minute = 0; if(year > 99) year = 23; if(month == 0 || month > 12) month = 1; if(day == 0 || day > 31) day = 1; } // 保存时间日期到EEPROM void Save_Time_To_EEPROM() { eeprom_update_byte((uint8_t*)EEPROM_TIME_HOUR_ADDR, hour); eeprom_update_byte((uint8_t*)EEPROM_TIME_MINUTE_ADDR, minute); eeprom_update_byte((uint8_t*)EEPROM_DATE_YEAR_ADDR, year); eeprom_update_byte((uint8_t*)EEPROM_DATE_MONTH_ADDR, month); eeprom_update_byte((uint8_t*)EEPROM_DATE_DAY_ADDR, day); } // 初始化定时器1 (1秒中断) void Timer1_Init() { // 设置定时器1为CTC模式 TCCR1B |= (1 << WGM12); // 设置预分频为1024 TCCR1B |= (1 << CS12) | (1 << CS10); // 设置比较值 (16MHz/1024 = 15625 ticks/sec, 15625 ticks = 1秒) OCR1A = 15625; // 启用比较匹配中断 TIMSK |= (1 << OCIE1A); } // 初始化按键引脚 void Buttons_Init() { // 设置按键引脚为输入,启用上拉电阻 DDRD &= ~((1<<SET_BUTTON) | (1<<ADD_BUTTON) | (1<<SUB_BUTTON)); PORTD |= (1<<SET_BUTTON) | (1<<ADD_BUTTON) | (1<<SUB_BUTTON); } // 按键扫描 void Key_Scan() { static uint8_t last_set_state = 1; static uint8_t last_add_state = 1; static uint8_t last_sub_state = 1; uint8_t current_set_state = PIND & (1<<SET_BUTTON); uint8_t current_add_state = PIND & (1<<ADD_BUTTON); uint8_t current_sub_state = PIND & (1<<SUB_BUTTON); // 检测设置按键按下 if(last_set_state && !current_set_state) { _delay_ms(20); // 消抖 if(!(PIND & (1<<SET_BUTTON))) { set_mode++; if(set_mode > 5) set_mode = 0; if(set_mode == 0) { // 退出设置模式,保存时间到EEPROM Save_Time_To_EEPROM(); } } } // 只在设置模式下检测加减按键 if(set_mode > 0) { // 检测增加按键按下 if(last_add_state && !current_add_state) { _delay_ms(20); // 消抖 if(!(PIND & (1<<ADD_BUTTON))) { switch(set_mode) { case 1: // 增加小时 hour = (hour + 1) % 24; break; case 2: // 增加分钟 minute = (minute + 1) % 60; break; case 3: // 增加年 year = (year + 1) % 100; break; case 4: // 增加月 month = (month % 12) + 1; break; case 5: // 增加日 day = (day % 31) + 1; break; } } } // 检测减少按键按下 if(last_sub_state && !current_sub_state) { _delay_ms(20); // 消抖 if(!(PIND & (1<<SUB_BUTTON))) { switch(set_mode) { case 1: // 减少小时 hour = (hour == 0) ? 23 : hour - 1; break; case 2: // 减少分钟 minute = (minute == 0) ? 59 : minute - 1; break; case 3: // 减少年 year = (year == 0) ? 99 : year - 1; break; case 4: // 减少月 month = (month == 1) ? 12 : month - 1; break; case 5: // 减少日 day = (day == 1) ? 31 : day - 1; break; } } } } last_set_state = current_set_state; last_add_state = current_add_state; last_sub_state = current_sub_state; } // 检查闹钟 void Check_Alarms() { static uint8_t alarm1_triggered = 0; static uint8_t alarm2_triggered = 0; // 检查闹钟1 if(alarm1.enabled && !alarm1_triggered && hour == alarm1.hour && minute == alarm1.minute && second == 0) { alarm1_triggered = 1; PORTB |= (1<<LED_PIN); // 打开LED } // 检查闹钟2 if(alarm2.enabled && !alarm2_triggered && hour == alarm2.hour && minute == alarm2.minute && second == 0) { alarm2_triggered = 1; PORTB |= (1<<LED_PIN); // 打开LED } // 每分钟重置闹钟触发标志 if(second == 0) { alarm1_triggered = 0; alarm2_triggered = 0; } // 如果LED亮起,检测按键关闭 if(PORTB & (1<<LED_PIN)) { if(!(PIND & (1<<SET_BUTTON)) || !(PIND & (1<<ADD_BUTTON)) || !(PIND & (1<<SUB_BUTTON))) { PORTB &= ~(1<<LED_PIN); // 关闭LED } } } // 定时器1比较匹配中断服务程序 ISR(TIMER1_COMPA_vect) { // 更新时间 second++; if(second >= 60) { second = 0; minute++; if(minute >= 60) { minute = 0; hour++; if(hour >= 24) { hour = 0; // 日期增加逻辑 day++; uint8_t max_day = 31; // 处理不同月份的天数 if(month == 4 || month == 6 || month == 9 || month == 11) { max_day = 30; } else if(month == 2) { // 简单处理2月天数(不考虑闰年) max_day = 28; } if(day > max_day) { day = 1; month++; if(month > 12) { month = 1; year++; if(year > 99) year = 0; } } } } } // 更新闪烁状态 (0.5秒周期) timer1_counter++; if(timer1_counter >= 5) { // 10次 = 1秒 (0.1秒中断) timer1_counter = 0; blink_state = !blink_state; } // 检查闹钟 Check_Alarms(); } int main(void) { // 初始化端口 DDRB |= (1<<LED_PIN); // LED引脚为输出 PORTB &= ~(1<<LED_PIN); // 初始关闭LED // 初始化按键 Buttons_Init(); // 初始化LCD LCD_Init(); // 从EEPROM加载时间 Load_Time_From_EEPROM(); // 初始化定时器 Timer1_Init(); // 启用全局中断 sei(); // 清屏并显示欢迎信息 LCD_Write_Command(0x01); LCD_Set_Cursor(0, 3); LCD_Display_String("AVR Clock"); LCD_Set_Cursor(1, 2); LCD_Display_String("Initializing..."); delay_ms(1000); LCD_Write_Command(0x01); while(1) { // 扫描按键 Key_Scan(); // 更新显示 if(set_mode == 0) { Display_Time(); } else { Display_Set_Mode(); } // 短暂延迟 delay_ms(100); } return 0; }
05-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值