51单片机---编程实现流水灯----键盘控制数码管显示--利用74LS164扩展并行输出口---定时中断方式驱动一个数码管

目录

基于51单片机,用c语言编程实现流水灯

代码:

使用C语言编写的基于51单片机的键盘控制数码管显示

代码:

基于51单片机,用c语言编程实现利用74LS164扩展并行输出口

代码:

基于51单片机,用c语言编程实现定时中断方式驱动一个数码管 

代码: 


基于51单片机,用c语言编程实现流水灯

代码:

1-

#include 

// 定义延时时间(单位:毫秒)
#define DELAY_TIME 500

// 左往右亮流水灯
void leftToRight() {
    unsigned char pattern = 0x01;
    
    while (1) {
        P1 = pattern;
        pattern <<= 1;
        
        if (pattern == 0x00) {
            pattern = 0x01;
        }
        
        delay();
    }
}

// 右往左亮流水灯
void rightToLeft() {
    unsigned char pattern = 0x80;
    
    while (1) {
        P1 = pattern;
        pattern >>= 1;
        
        if (pattern == 0x00) {
            pattern = 0x80;
        }
        
        delay();
    }
}

// 左往右亮然后右往左亮流水灯
void leftThenRight() {
    unsigned char pattern = 0x01;
    unsigned char direction = 0;  // 0表示左往右,1表示右往左
    
    while (1) {
        P1 = pattern;
        
        if (direction == 0) {
            pattern <<= 1;
            
            if (pattern == 0x00) {
                pattern = 0x80;
                direction = 1;
            }
        } else {
            pattern >>= 1;
            
            if (pattern == 0x00) {
                pattern = 0x01;
                direction = 0;
            }
        }
        
        delay();
    }
}

// 延时函数
void delay(){
    unsigned int i, j;
    for(i=0; i

2-

#include  // 包含51单片机的寄存器定义和常量

// 定义延时函数
void delay(unsigned int time) {
  unsigned int i, j;
  for (i = 0; i < time; i++) {
    for (j = 0; j < 125; j++) {
      // 延时一段时间
    }
  }
}

void main() {
  unsigned char pattern = 0x01; // 流水灯的显示模式,初始为第一个LED亮,其余LED灭

  while (1) {
    P1 = pattern; // 将当前模式的值写入P1口控制LED灯亮灭
    delay(500); // 延时一段时间,控制流水灯移动速度

    pattern <<= 1; // 模式左移一位,实现流水灯效果

    // 如果已经移到最后一颗LED,重新回到第一个LED
    if (pattern == 0x00) {
      pattern = 0x01;
    }
  }
}

上述代码中,使用P1口控制了8颗LED灯,通过将不同的模式值写入P1口,实现了流水灯灯光在8颗LED之间的移动。delay函数用于延时一定的时间,控制流水灯移动的速度。流水灯效果通过将模式值左移一位并判断是否移到最后一颗LED来实现。

使用C语言编写的基于51单片机的键盘控制数码管显示


最终版:

1-

#include 
sbit key1 = P2^0;
sbit key2 = P2^1;

// 定义数码管显示的数字
unsigned char code digit[] = {
    0xC0,  // 0
    0xF9,  // 1
    0xA4,  // 2
    0xB0,  // 3
    0x99,  // 4
    0x92,  // 5
    0x82,  // 6
    0xF8,  // 7
    0x80,  // 8
    0x90   // 9
};

// 定义延时函数
void delay(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 120; j++);
    }
}

void main() {
    unsigned char i = 0;
    unsigned char direction = 1;  // 1表示从小到大,0表示从大到小

    // 设置P1口为输出
    P1 = 0xFF;
    while (1) 
	{
        if (key1 == 0) {  // 第一个按键按下
			delay(200);
			if(key1 == 0)
            	direction = 1;  // 从小到大
        }
        if (key2 == 0) {  // 第二个按键按下
			delay(200);
			if(key2 == 0)
            	direction = 0;  // 从大到小
        }

        if (direction) {  // 从小到大
			i=0;
            P1 = digit[i];
            i++;
            if (i == 8) {
                i = 0;
            }
        } else {  // 从大到小
			i = 8;
            P1 = digit[i];
            i--;
            if (i == 0) {
                i = 8;
            }
        }

        delay(500);  // 延时500ms
    }
}

2-

#include 

// 数码管显示函数
void displayDigit(unsigned char digit) {
    unsigned char digitMap[] = {
        0b00111111,  // 数字0的7段码
        0b00000110,  // 数字1的7段码
        0b01011011,  // 数字2的7段码
        0b01001111,  // 数字3的7段码
        0b01100110,  // 数字4的7段码
        0b01101101,  // 数字5的7段码
        0b01111101,  // 数字6的7段码
        0b00000111,  // 数字7的7段码
        0b01111111,  // 数字8的7段码
        0b01101111   // 数字9的7段码
    };

// 延时函数
void delay() {
    // 延时逻辑
    // ...
}

int main() {
    unsigned char number = 0; // 初始数字为0

    while (1) {
        if (P1 == 0xFE) { // 第一个按键按下
            // 从大到小变化
            for (unsigned char i = number; i >= 0; i--) {
                number = i;
                displayDigit(number);
                delay();
            }
        }

        if (P1 == 0xFD) { // 第二个按键按下
            // 从小到大变化
            for (unsigned char i = number; i <= 9; i++) {
                number = i;
                displayDigit(number);
                delay();
            }
        }
    }

    return 0;
}

用于基于51单片机实现键盘控制数码管的显示(共阳极显示):

#include 

// 定义键盘引脚和数码管引脚连接方式
#define KEYPAD_PORT P1
#define DISPLAY_PORT P2

// 声明函数
void delay(unsigned int ms);
unsigned char readKeypad();
void displayDigit(unsigned char digit);

// 全局变量
unsigned char displayNumber = 0;

// 主函数
void main() {
  unsigned char key;
  
  while(1) {
    key = readKeypad(); // 检测键盘按键状态
    
    // 检测数字键
    if(key >= '0' && key <= '9') {
      displayNumber = key - '0'; // 更新显示数字
    }
    // 检测按下第一个键
    else if(key == 'A') {
      if(displayNumber > 0) {
        displayNumber--; // 更新显示数字
      }
    }
    // 检测按下第二个键
    else if(key == 'B') {
      if(displayNumber < 9) {
        displayNumber++; // 更新显示数字
      }
    }
    
    displayDigit(displayNumber); // 显示数字到数码管
  }
}

// 延时函数
void delay(unsigned int ms) {
  unsigned int i, j;
  for(i = 0; i < ms; i++) {
    for(j = 0; j < 123; j++);
  }
}

// 读取键盘状态
unsigned char readKeypad() {
  unsigned char row, col;
  
  // 设置列为输入,行为输出
  KEYPAD_PORT = 0xF0;
  P0 = 0xFF;
  
  // 检测哪一行被按下
  row = KEYPAD_PORT & 0xF0;
  
  // 如果无按键按下
  if(row == 0xF0) {
    return 0; // 返回0表示无按键按下
  }
  
  // 延时,等待按键稳定
  delay(10);
  
  // 检测列是否有响应
  col = KEYPAD_PORT & 0xF0;
  
  // 检测按下的键值
  if(col == 0xE0) return '1';
  if(col == 0xD0) return '2';
  if(col == 0xB0) return '3';
  if(col == 0x70) return 'A';
  if(col == 0xD0) return '4';
  if(col == 0xB0) return '5';
  if(col == 0x70) return '6';
  if(col == 0xE0) return 'B';
  if(col == 0xB0) return '7';
  if(col == 0x70) return '8';
  if(col == 0xE0) return '9';
  if(col == 0xD0) return '0';
  
  return 0; // 返回0表示无按键按下
}

// 数码管显示函数
void displayDigit(unsigned char digit) {
  unsigned char digitPattern;
  switch(digit) {
    case 0: digitPattern = 0xC0; break; // 共阳极的编码方式,可根据具体数码管更改
    case 1: digitPattern = 0xF9; break;
    case 2: digitPattern = 0xA4; break;
    case 3: digitPattern = 0xB0; break;
    case 4: digitPattern = 0x99; break;
    case 5: digitPattern = 0x92; break;
    case 6: digitPattern = 0x82; break;
    case 7: digitPattern = 0xF8; break;
    case 8: digitPattern = 0x80; break;
    case 9: digitPattern = 0x98; break;
    default: digitPattern = 0xFF;
  }
  
  DISPLAY_PORT = digitPattern; // 输出到数码管
}

代码:

#include  // 包含51单片机的寄存器定义和常量

// 定义延时函数
void delay(unsigned int time) {
  unsigned int i, j;
  for (i = 0; i < time; i++) {
    for (j = 0; j < 125; j++) {
      // 延时一段时间
    }
  }
}

void main() {
  unsigned char seg_code[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; // 数码管的段码值
  unsigned char keys[4][4] = {{0x01, 0x02, 0x03, 0x0F},
                              {0x04, 0x05, 0x06, 0x0E},
                              {0x07, 0x08, 0x09, 0x0D},
                              {0x00, 0x00, 0x00, 0x0C}}; // 键盘矩阵映射

  unsigned char keycode, row, col, digit;

  P2 = 0xFF; // 设置P2口为输入模式
  P0 = 0x00; // 初始化P0口

  while (1) {
    for (row = 0; row < 4; row++) {
      P2 = ~(0x01 << row); // 设置当前行为低电平
      delay(10); // 延时一段时间,等待稳定

      col = P2 & 0x0F; // 获取当前列的键值

      if (col != 0x0F) { // 如果当前列有按键按下
        // 查找按下的键值
        if (col == 0x0E) {
          digit = 0; // 1键按下
        } else if (col == 0x0D) {
          digit = 1; // 2键按下
        } else if (col == 0x0B) {
          digit = 2; // 3键按下
        } else if (col == 0x07) {
          digit = 3; // 4键按下
        }

        // 显示按键对应的数字
        if (keys[row][digit] != keycode) {
          keycode = keys[row][digit];
          P0 = seg_code[keycode]; // 数码管显示对应的数字
        }
      }
    }
  }
}

上述代码中,使用P2口作为键盘的输入引脚,并通过设置相应的行和列的电平状态,来判断按下的键值。根据按下的键值,在数码管上显示对应的数字。seg_code数组中存储了数码管的段码值,keys数组中存储了键盘矩阵的映射。

基于51单片机,用c语言编程实现利用74LS164扩展并行输出口

代码:

#include 

// 延时函数
void delay(unsigned int time) {
  unsigned int i, j;
  for (i = 0; i < time; i++) {
    for (j = 0; j < 125; j++) {
      // 延时一段时间
    }
  }
}

// 数据写入74LS164
void writeData(unsigned char data) {
  unsigned char i;
  P1 = data; // 将数据写入P1口
  for (i = 0; i < 8; i++) {
    P2 &= ~0x02; // 将74LS164的DS引脚置低
    P2 |= 0x02; // 将74LS164的DS引脚置高,写入数据
    data >>= 1; // 数据右移1位,准备写入下一位
  }
  P2 &= ~0x01; // 将74LS164的ST_CP引脚置低
  P2 |= 0x01; // 将74LS164的ST_CP引脚置高,数据锁存到输出端口
}

void main() {
  while (1) {
    // 输出的数据
    unsigned char data = 0xFF; // 11111111

    // 将数据写入74LS164
    writeData(data);

    // 延时一段时间
    delay(100); // 延时100ms

    // 输出的数据
    data = 0x00; // 00000000

    // 将数据写入74LS164
    writeData(data);

    // 延时一段时间
    delay(100); // 延时100ms
  }
}

上述代码中,利用P2口控制74LS164扩展并行输出,通过P1口向74LS164输入数据,然后通过控制P2口的引脚(DS和ST_CP),将P1口输入的数据从74LS164并行输出端口传输到外部设备(例如LED等)。


 最终:

#include 
#define uchar unsigned char
#define uint unsigned int

sbit SDA = P1 ^ 0; //定义IIC总线数据线
sbit SCL = P1 ^ 1; //定义IIC总线时钟线

uchar code digit[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90}; //定义数码管显示的数字

void delay(uint z) //延时函数
{
    uint x, y;
    for (x = z; x > 0; x--)
        for (y = 110; y > 0; y--)
            ;
}

void write_byte(uchar dat) //写入一个字节
{
    uchar i;
    for (i = 0; i < 8; i++)
    {
        SDA = dat >> (7 - i);
        SCL = 1;
        delay(1);
        SCL = 0;
    }
}

void write_data(uchar addr, uchar dat) //写入一个字节数据到指定地址
{
    SDA = 0;
    SCL = 0;
    SCL = 1;
    write_byte(0xa0);
    SCL = 1;
    write_byte(addr);
    SCL = 1;
    write_byte(dat);
    SCL = 1;
}

void main()
{
    uchar i;
    while (1)
    {
        for (i = 0; i < sizeof(digit); i++)
        {
            write_data(i + 1, digit[i]);
            delay(100);
        }
    }
}


74LS164 是一个 8 位串行输入并行输出的移位寄存器,可以用来扩展单片机的输出口。下面是一个基于 51 单片机,用 C 语言编程实现利用 74LS164 扩展并行输出口的例子:

#include
#define uchar unsigned char
#define uint unsigned int

sbit DS=P2^0;
sbit SHCP=P2^1;
sbit STCP=P2^2;

void delay(uint z)
{
    uint x,y;
    for(x=z;x>0;x--)
        for(y=110;y>0;y--);
}

void main()
{
    uchar i;
    while(1)
    {
        for(i=0;i<8;i++)
        {
            DS=0;
            SHCP=0;
            SHCP=1;
            DS=(P1>>i)&0x01;
            SHCP=0;
        }
        STCP=1;
        STCP=0;
        delay(100);
    }
}
  • 在这个例子中,使用了三个 IO 口来控制 74LS164。DS 口用来输入数据,SHCP 口用来控制数据的移位,STCP 口用来控制数据的锁存。
  • 在主函数中,使用一个循环来控制数据的输出。首先将 DS 口置为低电平,然后将 SHCP 口置为低电平。接着将 SHCP 口置为高电平,然后将 DS 口设置为需要输出的数据。最后将 SHCP 口置为低电平。这样就完成了一次数据的移位。
  • 当移位完成后,将 STCP 口置为高电平,然后再置为低电平。这样就完成了一次数据的锁存。

  • 这个例子中,使用了三个 IO 口来控制 74LS164。DS 口用来输入数据,SHCP 口用来控制数据的移位,STCP 口用来控制数据的锁存。
  • 在主函数中,使用一个循环来控制数据的输出。首先将 DS 口置为低电平,然后将 SHCP 口置为低电平。接着将 SHCP 口置为高电平,然后将 DS 口设置为需要输出的数据。最后将 SHCP 口置为低电平。这样就完成了一次数据的移位。
  • 当移位完成后,将 STCP 口置为高电平,然后再置为低电平。这样就完成了一次数据的锁存。
  • 在这个例子中,使用了 74LS164 来扩展单片机的输出口。DS 口用来输入数据,SHCP 口用来控制数据的移位,STCP 口用来控制数据的锁存。在主函数中,使用一个循环来控制数据的输出。首先将 DS 口置为低电平,然后将 SHCP 口置为低电平。接着将 SHCP 口置为高电平,然后将 DS 口设置为需要输出的数据。最后将 SHCP 口置为低电平。这样就完成了一次数据的移位。当移位完成后,将 STCP 口置为高电平,然后再置为低电平。这样就完成了一次数据的锁存。

基于51单片机,用c语言编程实现定时中断方式驱动一个数码管 

方一: 

1--

#include 
#define uchar unsigned char
#define uint unsigned int

sbit SDA = P1 ^ 0; //定义IIC总线数据线
sbit SCL = P1 ^ 1; //定义IIC总线时钟线

uchar code digit[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90}; //定义数码管显示的数字

void delay(uint z) //延时函数
{
    uint x, y;
    for (x = z; x > 0; x--)
        for (y = 110; y > 0; y--)
            ;
}

void write_byte(uchar dat) //写入一个字节
{
    uchar i;
    for (i = 0; i < 8; i++)
    {
        SDA = dat >> (7 - i);
        SCL = 1;
        delay(1);
        SCL = 0;
    }
}

void write_data(uchar addr, uchar dat) //写入一个字节数据到指定地址
{
    SDA = 0;
    SCL = 0;
    SCL = 1;
    write_byte(0xa0);
    SCL = 1;
    write_byte(addr);
    SCL = 1;
    write_byte(dat);
    SCL = 1;
}

void timer() interrupt 1 //定时器中断函数
{
    static uchar cnt = 0; //静态变量,只初始化一次,每次调用保留上次的值
    TH0 = (65536 - 50000) / 256; //重新赋初值,定时50ms
    TL0 = (65536 - 50000) % 256;
    cnt++;
    if (cnt == sizeof(digit))
        cnt = 0;
    write_data(cnt + 1, digit[cnt]); //显示下一个数字
}

void main()
{
    TMOD |= 0x01; //设置定时器T0为模式1(16位自动重装载)
    TH0 = (65536 - 50000) / 256; //赋初值,定时50ms
    TL0 = (65536 - 50000) % 256;
    ET0 = 1; //开启定时器T0中断
    EA = 1; //开启总中断
    TR0 = 1; //启动定时器T0

    while (1)
        ;
}

2--

代码: 

#include 

// 数码管显示表,从0到9
unsigned char displayTable[] = {
  0xC0,   // 0
  0xF9,   // 1
  0xA4,   // 2
  0xB0,   // 3
  0x99,   // 4
  0x92,   // 5
  0x82,   // 6
  0xF8,   // 7
  0x80,   // 8
  0x90    // 9
};

// 共阴极数码管引脚连接的IO口
sbit digit1 = P1^0;  // 第一位数码管
sbit digit2 = P1^1;  // 第二位数码管
sbit digit3 = P1^2;  // 第三位数码管
sbit digit4 = P1^3;  // 第四位数码管

// 数码管显示的值
volatile unsigned char displayValue = 0;

// 定时器中断处理函数
void timerInterrupt() interrupt 1 {
  static unsigned char digit = 0;  // 当前显示的位数
  
  // 设置当前要显示的数码管
  switch (digit) {
    case 0:
      digit1 = 1;
      digit2 = 0;
      digit3 = 0;
      digit4 = 0;
      P0 = displayTable[displayValue % 10];  // 显示个位数
      break;
    case 1:
      digit1 = 0;
      digit2 = 1;
      digit3 = 0;
      digit4 = 0;
      P0 = displayTable[displayValue / 10 % 10];  // 显示十位数
      break;
    case 2:
      digit1 = 0;
      digit2 = 0;
      digit3 = 1;
      digit4 = 0;
      P0 = displayTable[displayValue / 100 % 10];  // 显示百位数
      break;
    case 3:
      digit1 = 0;
      digit2 = 0;
      digit3 = 0;
      digit4 = 1;
      P0 = displayTable[displayValue / 1000];  // 显示千位数
      break;
  }
  
  digit++;  // 切换到下一个要显示的数码管
  if (digit >= 4) {
    digit = 0;
  }
}

void main() {
  TMOD = 0x01;      // 设置定时器0为模式1
  TH0 = 0xFC;      // 设置定时器0的初值,定时100us
  TL0 = 0x67;
  ET0 = 1;         // 允许定时器0中断
  EA = 1;          // 允许总中断
  TR0 = 1;         // 启动定时器0
  
  while (1) {
    // 更新数码管显示的值,可以通过其他方式改变displayValue的值
    // 这里只简单地每隔一段时间递增displayValue,模拟数码管的显示
    displayValue++;
    if (displayValue > 9999) {
      displayValue = 0;
    }
  }
}

上述代码中,使用定时器0和定时中断驱动数码管的显示,通过计时中断的方式实现数码管的动态显示。其中,P0口用于连接数码管对应的引脚,需要根据实际连接情况进行修改。数码管共阴极连接的IO口通过sbit定义,根据具体的引脚连接情况进行修改。

定时器0的初始值根据实际需求进行调整,设置定时器0的初值和模式来控制定时器中断的频率。在定时器中断处理函数中,根据当前要显示的数码管位数和显示的值,设置对应的IO口和数码管段码进行显示。

方法二:

代码:

#include
#define uchar unsigned char
#define uint unsigned int

uchar code table[]={
    0x3f,0x06,0x5b,0x4f,
    0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,
    0x39,0x5e,0x79,0x71
};

uchar num=0;
uint cnt=0;

void delay(uint z)
{
    uint x,y;
    for(x=z;x>0;x--)
        for(y=110;y>0;y--);
}

void main()
{
    TMOD=0x01;
    TH0=(65536-45872)/256;
    TL0=(65536-45872)%256;
    EA=1;
    ET0=1;
    TR0=1;
    while(1)
    {
        P1=table[num];
        delay(100);
        P1=0xff;
        delay(100);
    }
}

void timer_0() interrupt 1
{
    TH0=(65536-45872)/256;
    TL0=(65536-45872)%256;
    cnt++;
    if(cnt==100)
    {
        cnt=0;
        num++;
        if(num==16)
            num=0;
    }
}

 这个例子使用定时器 T0 的中断实现长时间定时,驱动一个数码管。在这个例子中,使用了一个计数器 cnt 来计算定时器 T0 中断的次数,当计数器 cnt 等于 100 时,就将计数器清零,并将 num 加一。当 num 等于 16 时,将 num 清零。在主函数中,使用 P1 来控制数码管的显示。

  • 首先,需要了解一下 51 单片机的定时器。51 单片机有两个定时器,分别是定时器 T0 和定时器 T1。这两个定时器都可以用来产生中断。
  • 在这个例子中,使用了定时器 T0 来产生中断。在主函数中,首先设置了定时器 T0 的工作模式为模式 1(TMOD=0x01),这表示定时器 T0 工作在 16 位自动重装载模式。然后设置了定时器 T0 的初值(TH0 和 TL0)为 (65536-45872),这样就可以让定时器 T0 每隔一段时间产生一次中断。
  • 在主函数的 while 循环中,使用 P1 来控制数码管的显示。每隔一段时间,就将 num 加一,并将 num 显示在数码管上。当 num 等于 16 时,将 num 清零。
  • 在 timer_0() 函数中,首先重新设置了定时器 T0 的初值(TH0 和 TL0),然后将计数器 cnt 加一。当计数器 cnt 等于 100 时,就将计数器清零,并将 num 加一。当 num 等于 16 时,将 num 清零。


使用定时中断方式驱动一个数码管

#include 
#define uchar unsigned char
#define uint unsigned int

sbit SDA = P1 ^ 0; //定义IIC总线数据线
sbit SCL = P1 ^ 1; //定义IIC总线时钟线

uchar code digit[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90}; //定义数码管显示的数字

void delay(uint z) //延时函数
{
    uint x, y;
    for (x = z; x > 0; x--)
        for (y = 110; y > 0; y--)
            ;
}

void write_byte(uchar dat) //写入一个字节
{
    uchar i;
    for (i = 0; i < 8; i++)
    {
        SDA = dat >> (7 - i);
        SCL = 1;
        delay(1);
        SCL = 0;
    }
}

void write_data(uchar addr, uchar dat) //写入一个字节数据到指定地址
{
    SDA = 0;
    SCL = 0;
    SCL = 1;
    write_byte(0xa0);
    SCL = 1;
    write_byte(addr);
    SCL = 1;
    write_byte(dat);
    SCL = 1;
}

void timer() interrupt 1 //定时器中断函数
{
    static uchar cnt = 0; //静态变量,只初始化一次,每次调用保留上次的值
    TH0 = (65536 - 50000) / 256; //重新赋初值,定时50ms
    TL0 = (65536 - 50000) % 256;
    cnt++;
    if (cnt == sizeof(digit))
        cnt = 0;
    write_data(cnt + 1, digit[cnt]); //显示下一个数字
}

void main()
{
    TMOD |= 0x01; //设置定时器T0为模式1(16位自动重装载)
    TH0 = (65536 - 50000) / 256; //赋初值,定时50ms
    TL0 = (65536 - 50000) % 256;
    ET0 = 1; //开启定时器T0中断
    EA = 1; //开启总中断
    TR0 = 1; //启动定时器T0

    while (1)
        ;
}

 

你可能感兴趣的:(单片机,平时学习,计算机外设)