目录
基于51单片机,用c语言编程实现流水灯
代码:
使用C语言编写的基于51单片机的键盘控制数码管显示
代码:
基于51单片机,用c语言编程实现利用74LS164扩展并行输出口
代码:
基于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来实现。
最终版:
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;
}
#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
数组中存储了键盘矩阵的映射。
#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 口置为高电平,然后再置为低电平。这样就完成了一次数据的锁存。
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)
;
}