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,重新回到第一个LEDif (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,  // 00xF9,  // 10xA4,  // 20xB0,  // 30x99,  // 40x92,  // 50x82,  // 60xF8,  // 70x80,  // 80x90   // 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; // 初始数字为0while (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// 将数据写入74LS164writeData(data);// 延时一段时间delay(100); // 延时100ms// 输出的数据data = 0x00; // 00000000// 将数据写入74LS164writeData(data);// 延时一段时间delay(100); // 延时100ms}
}

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


 最终:

#include 
#define uchar unsigned char
#define uint unsigned intsbit 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 intsbit 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 intsbit 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; //重新赋初值,定时50msTL0 = (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; //赋初值,定时50msTL0 = (65536 - 50000) % 256;ET0 = 1; //开启定时器T0中断EA = 1; //开启总中断TR0 = 1; //启动定时器T0while (1);
}

2--

代码: 

#include // 数码管显示表,从0到9
unsigned char displayTable[] = {0xC0,   // 00xF9,   // 10xA4,   // 20xB0,   // 30x99,   // 40x92,   // 50x82,   // 60xF8,   // 70x80,   // 80x90    // 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为模式1TH0 = 0xFC;      // 设置定时器0的初值,定时100usTL0 = 0x67;ET0 = 1;         // 允许定时器0中断EA = 1;          // 允许总中断TR0 = 1;         // 启动定时器0while (1) {// 更新数码管显示的值,可以通过其他方式改变displayValue的值// 这里只简单地每隔一段时间递增displayValue,模拟数码管的显示displayValue++;if (displayValue > 9999) {displayValue = 0;}}
}

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

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

方法二:

代码:

#include
#define uchar unsigned char
#define uint unsigned intuchar 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 intsbit 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; //重新赋初值,定时50msTL0 = (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; //赋初值,定时50msTL0 = (65536 - 50000) % 256;ET0 = 1; //开启定时器T0中断EA = 1; //开启总中断TR0 = 1; //启动定时器T0while (1);
}

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部