串口通信 day48

单片机

一:基础概念

一:单片机最小系统

单片机:电源+时钟(晶振)+复位 //实现的最小组件

电源:5V直流

时钟(晶振):决定系统运行的速率 一般12M(不超过50M),因为过快导致稳定性,抗干扰性能下降,

​ 分为分频和倍频,一般都是分频(1/(2*6)分频)

复位:电平信号(高/低) 2种:先上升沿,在下降沿; 先下降沿,后上升沿

原理图:表示器件的逻辑连接关系

PCB:表示器件物理连接关系

二:RAM/ROM 芯片自带

RAM :随机存储器 (访问速度快) 4kb //掉电数据丢失

ROM :只读存储器 (访问速度慢) 100~200kb //掉电数据不丢失

三:发光二极管

单个二极管要求电压:0.5v~0.7v 一般给1v~2v 电流:10mv~MAX

四:流水灯

#include <reg51.h>

void delay_ms(unsigned int num)
{
	unsigned char i,j;
	while(num--)
	{
		i = 2;//看具体晶振大小
		j = 199;
	}
	do
	{
		while(--j);
	}while(--i);
}

void main(void)
{
	unsigned char dat = 0;
	
	while(1)
	{
		 P2 = 255 - dat++; //共阳极
		 delay_ms(500);
	};
}

五:显示数字

#include <reg51.h>

void delay_ms(unsigned int num)
{
	unsigned char i,j;
	while(num--)
	{
		i = 2;
		j = 199;
	}
	do
	{
		while(--j);
	}while(--i);
}

void digit_select(unsigned char digit)
{
	unsigned char num = P2;
	num &= ~(0x7 << 2);  //22 23 24 控制
	num |= (digit << 2);
	P2 = num;
}

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

void digit_show_num(unsigned long num)
{
 	unsigned char digits[8];
	int i = 0;  

	for (i = 7; i >= 0; i--) {
	    digits[i] = num % 10;
	    num /= 10;
	}
   
	while(1)
	{
		for(i=0;i<8;i++)
		{
			if(digits[i] != 0)
			{
				digit_select(7 - i);
				P0 = array[digits[i]]; 
				delay_ms(2);        
			}
		}
	}
}

void main(void)
{ 
	digit_show_num(65536);	//51单片机是8位系统,所以要long int	
}

六:74HC595(串转并)模块,点亮8*8LED点阵

信号名(简写)全称功能说明对应引脚
SERSerial Data串行数据输入(Data)14
SRCLK / SPCLKShift Register Clock移位寄存器时钟(移位控制)11
RCLKRegister Clock (Latch Clock)锁存时钟(控制输出)12
SRCLRShift Register Clear清除寄存器10
OEOutput Enable输出使能,低电平有效13
#include <reg51.h>
#include <intrins.h>

sbit SER  = P3^4;
sbit SHCP = P3^6;
sbit STCP = P3^5;
sbit BEEP = P2^5;

void delay_us(unsigned char us)
{
    while(us--)
    {
        _nop_(); _nop_(); _nop_(); _nop_(); // 4×NOP指令,大概1us
    }
}


void shift_out(unsigned char dat)
{
    unsigned char i;
    for(i = 0; i < 8; i++)
    {
		SHCP = 0;
        SER = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
		delay_us(1);	//如果移的太快,可能导致芯片识别不到上升沿
        SHCP = 1;
		delay_us(1);   //如果移的太快,可能导致芯片识别不到上升沿
    }
   //最后再产生一个上升沿
    STCP = 0;
	delay_us(1);
    STCP = 1;
}

void main(void)
{
    while(1)
    {
		BEEP = 0;
        shift_out(0xff);
		P0 = 0x00;
		delay_us(100);
		P0 = 0xFF;
    }
}
#include <reg51.h>
#include <intrins.h>

sbit SER  = P3^4;
sbit SHCP = P3^6;
sbit STCP = P3^5;
sbit BEEP = P2^5;

void delay_us(unsigned char us)
{
    while(us--)
    {
        _nop_(); _nop_(); _nop_(); _nop_(); // 4×NOP指令,大概1us
    }
}


void shift_out(unsigned char dat)
{
    unsigned char i;
    for(i = 0; i < 8; i++)
    {
		SHCP = 0;
        SER = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
		delay_us(1);	//如果移的太快,可能导致芯片识别不到上升沿
        SHCP = 1;
		delay_us(1);   //如果移的太快,可能导致芯片识别不到上升沿
    }
   //最后再产生一个上升沿
    STCP = 0;
	delay_us(1);
    STCP = 1;
}

unsigned char xin_shape[8] = {
    0x99,
    0x00,
    0x00,
    0x00,
    0x81,
    0xC3,
    0xE7,
	0xFF
};


void main(void)
{
	int i = 0;
	while(1)
    {
		for(i = 0;i<8;i++)
		{
			shift_out ((1 << i) ); // 列数据(高电平表示点亮)
	    	P0 = xin_shape[7-i];          
	    	delay_us(100);
			P0 = 0xFF;  //消影 	
		}	
		BEEP = 0;
    }
}

#include <reg51.h>
#include <intrins.h>

sbit SER  = P3^4;
sbit SHCP = P3^6;
sbit STCP = P3^5;
sbit BEEP = P2^5;

void delay_ms(unsigned int num)
{
	unsigned char i,j;
	while(num--)
	{
		i = 2;//看具体晶振大小
		j = 199;
	}
	do
	{
		while(--j);
	}while(--i);
}

void delay_us(unsigned char us)
{
    while(us--)
    {
        _nop_(); _nop_(); _nop_(); _nop_(); // 4×NOP指令,大概1us
    }
}


void shift_out(unsigned char dat)
{
    unsigned char i;
    for(i = 0; i < 8; i++)
    {
		SHCP = 0;
        SER = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
		delay_us(1);	//如果移的太快,可能导致芯片识别不到上升沿
        SHCP = 1;
		delay_us(1);   //如果移的太快,可能导致芯片识别不到上升沿
    }
   //最后再产生一个上升沿
    STCP = 0;
	delay_us(1);
    STCP = 1;
}

unsigned char num_font_0_9[10 * 8] = {
    0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, // 0
    0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x7E, // 1
    0x7E, 0x42, 0x42, 0x06, 0x1C, 0x30, 0x60, 0x7E, // 2
    0x7E, 0x42, 0x42, 0x1C, 0x1C, 0x42, 0x42, 0x7E, // 3
    0x0C, 0x1C, 0x2C, 0x4C, 0x7E, 0x7E, 0x0C, 0x0C, // 4
    0x7E, 0x60, 0x60, 0x7C, 0x06, 0x06, 0x46, 0x7E, // 5
    0x3C, 0x60, 0x40, 0x7C, 0x66, 0x42, 0x66, 0x3C, // 6
    0x7E, 0x42, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, // 7
    0x3C, 0x66, 0x66, 0x3C, 0x66, 0x42, 0x66, 0x3C, // 8
    0x3C, 0x66, 0x66, 0x3E, 0x02, 0x06, 0x0C, 0x38  // 9
};

void main(void)
{
	unsigned char i = 0;
	unsigned char j = 0;
	unsigned char k = 0;
	unsigned char num = 0;
	while(1)
	{
		if(j % 8 == 0)
			num = 80;
		else
			num = 20;

		for(k = 0; k < num; k++)
		{
			for(i = 0; i < 8; i++)
			{
				shift_out(1 << (7 - i));	//// 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01	 
				P0 = ~num_font_0_9[i + j];	//i + j 表示当前这一帧要显示的列数据
				delay_us(100);
				P0 = 0xff;
				  
			}
		}

		j++;
		if(j > 72)
			j = 0;
	}
}



七:按键

#include <reg51.h>

void main(void)
{
	while(1)
	{
		if(!(P3 & (1 << 3)))
			P2 = 0x55; // 0101 0101
		else
			P2 = 0xFF; // 1111 1111
		if(!(P3 & (1 << 2)))
			P2 = 0xaa; // 1010 1010
	}
}
#include <reg51.h>
sbit BEEP = P2^5;

void delay_ms(unsigned int num)
{
	unsigned char i,j;
	while(num--)
	{
		i = 2;//看具体晶振大小
		j = 199;
	}
	do
	{
		while(--j);
	}while(--i);
}

unsigned char code seg_table[] = {
    0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,  // 0~7
    0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71   // 8~F
};

void main(void)
{
	unsigned char i = 0;
	unsigned char j = 0;
	unsigned char key = 0;
	while(1)
	{
		BEEP = 1;
		for(i = 0;i<4;i++)
		{
			P1 = ~(P1 & (1 << i));
			for(j = 0;j<4;j++)
			{
				if(!(P1 & (1 <<j+4)))
				{
					key = 4*(3-j)+(3-i);
					P0 = seg_table[key];
					delay_ms(500);
					while(!(P1 & (1 <<j+4)));
				}
			}
			
		}
	}
}

八:中断

一:外部中断
#include <reg51.h>

// 延时函数
void delay_ms(unsigned int num)
{
	unsigned char i, j;
	while(num--) {
		i = 2;
		j = 199;
		do {
			while (--j);
		} while (--i);
	}
}

// 点阵选择函数(保留未用)
void digit_select(unsigned char digit)  // 0~7
{
    unsigned char num = P2;
	num &= ~(0x7 << 2);	    
	num |= (digit << 2);
	P2 = num;	   
}

// 点阵数据(10个数字图案,每个8字节)
unsigned char code h_data[10 * 8] = 
{
	0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00,	// 0
	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x7E, // 1
	0x00, 0x3c, 0x08, 0x10, 0x20, 0x3c, 0x00, 0x00, // 2
	0x00, 0x3c, 0x04, 0x04, 0x3c, 0x04, 0x04, 0x3c, // 3
	0x00, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x04, 0x04, // 4
	0x3C, 0x20, 0x20, 0x3C, 0x04, 0x04, 0x3C, 0x00, // 5
	0x00, 0x3c, 0x20, 0x20, 0x3c, 0x24, 0x3c, 0x00, // 6
	0x00, 0x3c, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, // 7
	0x7E, 0xC3, 0xC3, 0x7E, 0xC3, 0xC3, 0xC3, 0x7E, // 8
	0x00, 0x18, 0x24, 0x24, 0x1C, 0x04, 0x24, 0x18  // 9
};

// 段码(未用,可保留)
unsigned char array[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

// 74HC595 引脚
sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;

// 简单延时
void delayn(unsigned char n)
{
	while(n--);
}

// 发送1字节数据到74HC595
void write_74hc595(unsigned char dat)
{
	unsigned char i = 0;
	for(i = 0; i < 8; i++)
	{
		SER = (dat & (1 << (7 - i))) ? 1 : 0;
		SRCLK = 0;   
		delayn(1);
		SRCLK = 1;
		delayn(1);      
	}
	RCLK = 0;
	delayn(1); 
	RCLK = 1;
}

// 外部中断0初始化
void eint0_init(void)
{
	IT0 = 1;    // 下降沿触发
	EX0 = 1;    // 开启INT0中断
	EA = 1;     // 开启总中断
}

// 当前显示的数字
unsigned char num = 0;

// 中断服务函数,显示数字 +1
void eint0_hanlder(void) interrupt 0 
{
	P2 = 0xf0;     // 可用于调试
	num++;
	if (num > 9)
		num = 0;
	P2 = ~num;     // 显示在 P2(可接LED)
}

// 外部中断1初始化(INT1,P3.3,下降沿触发)
void eint1_init(void) {
    IT1 = 1;   // 1 = 边沿触发(下降沿)
    EX1 = 1;   // 允许外部中断1
    EA  = 1;   // 总中断允许(一般只需设置一次)
}

// 外部中断1服务函数(中断号 2)
void eint1_handler(void) interrupt 2 {
    P2 = 0x0f; // 可用于调试或 LED 显示
    if (num == 0)
        num = 9;
    else
        num--;
    P2 = ~num; // 显示新的值
}


// 主函数
void main(void)
{
	unsigned char key = 0;
	unsigned char k = 0;
	unsigned char i = 0;
	unsigned char dst = 0;
	unsigned char j = 0;
	unsigned char abs = 0;

	eint0_init();  // 初始化外部中断
	eint1_init();
	while(1)		   // 显示当前 num 指向的数字
	{
		for(j = 0; j <= abs; j++)
		{
			for(k = 0; k < 30; k++)
			{
				for(i = 0; i < 8; i++)
				{
					write_74hc595(1 << (7 - i));             // 列选
					P0 = ~h_data[i + num * 8];               // 行码
					delayn(100);                             // 简单延时
					P0 = 0xff;                               // 消影
				}
			}
		}	
	}
}

二:定时器

TFO:定时器/计数器T0溢出中断标志。T0被允许计数以后,从初值开始加1计数,当最高位产生溢出时,由硬件置“1”TFO,向CPU请求中断,一直保持CPU响应该中断时,才由硬件清“O”TFO(TFO也可由程序查询清“O”)

TRO:定时器T0的运行控制位。该位由软件置位和清零。当GATE(TMOD.3)(第三位)=0,TR0=1时就允许T0开始计数,TR0=0时禁止T0计数。当GATE(TMOD.3)=1,TR1=0且INTO输入高电平时,才允许TO计数。

​ TRO=0 //停止计数

​ TRO = 1 //启动计数

​ GATE = 0 //直接计数

​ = 1 //INTO为高电平时计数

定时器/计数器工作模式寄存器TMOD:

定时和计数功能由特殊功能寄存器TMOD的控制位C/T进行选择,TMOD寄存器的各位信息如下表所列。可以看出,2个定时/计数器有4种操作模式,通过TMOD的M1和M0选择。2个定时/计数器的模式0、1和2都相同,模式3不同,各

//定时器0
#include <reg51.h>

// 硬件接口定义
sbit RCLK = P3^5;
sbit SRCLK = P3^6;
sbit SER = P3^4;

// 延时函数(简易版)
void delayn(unsigned char n) {
	while(n--);
}

// 74HC595 写入一个字节
void write_74hc595(unsigned char dat) {
	unsigned char i;
	for(i = 0; i < 8; i++) {
		SER = (dat & (1 << (7 - i))) ? 1 : 0;
		SRCLK = 0;
		delayn(1);
		SRCLK = 1;
		delayn(1);
	}
	RCLK = 0;
	delayn(1);
	RCLK = 1;
}

// 数码管图案数据(0~9)
unsigned char code h_data[10 * 8] = {
	0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00,	// 0
	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x7E, //1
	0x00, 0x3c, 0x08, 0x10, 0x20, 0x3c, 0x00, 0x00,//2
	0x00, 0x3c, 0x04, 0x04, 0x3c, 0x04, 0x04, 0x3c, //3
	0x00, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x04, 0x04, //4
	0x3C, 0x20, 0x20, 0x3C, 0x04, 0x04, 0x3C, 0x00,  //5
	0x00, 0x3c, 0x20, 0x20, 0x3c, 0x24, 0x3c, 0x00,  //6
	0x00, 0x3c, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, //7
	0x7E, 0xC3, 0xC3, 0x7E, 0xC3, 0xC3, 0xC3, 0x7E,  //8
	0x00, 0x18, 0x24, 0x24, 0x1C, 0x04, 0x24, 0x18 // 9
};

// 全局变量
unsigned char num = 0; // 当前显示的数字

// 外部中断0初始化(下降沿触发)
void eint0_init(void) {
	IT0 = 1;
	EX0 = 1;
	EA = 1;
}

// 外部中断0服务函数
void eint0_handler(void) interrupt 0 {
	P2 = 0xf0; // 可用于调试
	num++;
	if (num > 9) num = 0;
	P2 = ~num; // 可接 LED 显示数值
}

// 外部中断1初始化(INT1,P3.3,下降沿触发)
void eint1_init(void) {
    IT1 = 1;   // 1 = 边沿触发(下降沿)
    EX1 = 1;   // 允许外部中断1
    EA  = 1;   // 总中断允许(一般只需设置一次)
}

// 外部中断1服务函数(中断号 2)
void eint1_handler(void) interrupt 2 {
    P2 = 0x0f; // 可用于调试或 LED 显示
    if (num == 0)
        num = 9;
    else
        num--;
    P2 = ~num; // 显示新的值
}
 
void timer0_init(void)
{
	TH0 = 0x4C;
	TL0 = 0x00;		//15535/256
	TMOD &= ~(0x1<< 2);	
	TMOD &= ~(0x1<< 3);
	TMOD &= ~(0x3 << 0);
	TMOD |= (0x01 << 0);
	ET0 = 1;           // 允许定时器0中断 
	EA = 1;
	TR0 = 1;
}

void timer0_handler(void) interrupt 1
{
	static unsigned char timer0_num = 0;
	TH0 = 0x4C;
	TL0 = 0x00;
	TR0 = 1;

	timer0_num++;
	if(20 == timer0_num)
	{
		num++;
		if (num == 9)
        	num = 0;
		timer0_num = 0;
	}
}



// 主函数
void main(void)
{
	unsigned char key = 0;
	unsigned char k = 0;
	unsigned char i = 0;
	//unsigned char num = 0;
	unsigned char dst = 0;
	unsigned char j = 0;
	unsigned char abs = 0;
	eint0_init();
	timer0_init(); 
 	while(1)		   // 0   4    8  
	{
		for(j = 0; j <= abs; j++)
		{
			for(k = 0; k < 30; k++)
			{
				for(i = 0; i < 8; i++)
				{
					write_74hc595(1 << (7 - i));
					P0 = ~h_data[i + num * 8];
					delayn(100);
					P0 = 0xff;
				}
			}
		}	
	}
}
三:24小时时钟
#include <reg51.h>

unsigned char hour = 17;
unsigned char min = 59; 
unsigned char sec = 0;  

unsigned char code digit_table[] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F  // 9
};

void timer0_init(void)
{
	TH0 = 0x4C;
	TL0 = 0x00;		//15535/256
	TMOD &= ~(0x1<< 2);	
	TMOD &= ~(0x1<< 3);
	TMOD &= ~(0x3 << 0);
	TMOD |= (0x01 << 0);
	ET0 = 1;           // 允许定时器0中断 
	EA = 1;
	TR0 = 1;
}

void timer0_handler(void) interrupt 1
{
    static unsigned char timer0_num = 0;
    TH0 = 0x4C;
    TL0 = 0x00;
    if(++timer0_num >= 20)  // 20×50ms = 1s
    {
        timer0_num = 0;
        sec++;
        if(sec >= 60)
        {
            sec = 0;
            min++;
            if(min >= 60)
            {
                min = 0;
                hour++;
                if(hour >= 24)
                    hour = 0;
            }
        }
    }
}

void delay_ms(unsigned int num)
{
	unsigned char i,j;
	while(num--)
	{
		i = 2;
		j = 199;
	}
	do
	{
		while(--j);
	}while(--i);
}

void digit_select(unsigned char digit)
{
	unsigned char num = P2;
	num &= ~(0x7 << 2);  //22 23 24 控制
	num |= (digit << 2);
	P2 = num;
}


void digit_show_num()
{
    unsigned char digits[8];
    unsigned char i;

    digits[0] = hour / 10;      // 小时十位
    digits[1] = hour % 10;      // 小时个位
    digits[2] = 10;            
    digits[3] = min / 10;       // 分钟十位
    digits[4] = min % 10;       // 分钟个位
    digits[5] = 10;             
    digits[6] = sec / 10;       // 秒十位
    digits[7] = sec % 10;       // 秒个位
    for(i = 0; i < 8; i++)
    {
        digit_select(i);
        if(digits[i] == 10)     
            P0 = 0x40;          
        else
            P0 = digit_table[digits[7-i]];
        delay_ms(2);
    }
}

// 主函数
void main(void)
{
	timer0_init();
	while(1)
	{
		digit_show_num();
		delay_ms(100);
	} 
	
}

九:串口通信

通信:无线和有线

​ 单工 半双工 全双工

并行:多个数据线 串行:一根数据线

同步:通信双方使用同一个时钟,SPI信息帧,有CLK引脚

异步:通信双方使用不同时钟,双方要固定的数据帧(0起始,1停止)和传输速度(波特率,一般都是9600bps = 1s:单位时间传输了多少个码元,这里用二进制码元),无CLK引脚

空闲时总线保持高电平。起始信号:由高到低 起始信号:由低到高

数据位:5,6,7,8位 需要起始位:1~2位

eg:11001100 实际数据:0x33,数据头是低位

一:UART串口

#include <reg51.h>

unsigned char recv = 0;

unsigned char code digit_table[] = {
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
};

void digit_select(unsigned char digit)
{
	unsigned char num = P2;
	num &= ~(0x7 << 2);  
	num |= (digit << 2);
	P2 = num;
}

void serial_server() interrupt 4 
{
	if(TI)
	TI = 0;
	if(RI)
	RI = 0;
	recv = SBUF;

	switch(recv)
	{
		case '1':digit_select(0); P0 = digit_table[0];break;
		case '2':digit_select(1); P0 = digit_table[1];break;
		case '3':digit_select(2); P0 = digit_table[2];break;
		case '4':digit_select(3); P0 = digit_table[3];break;
		case '5':digit_select(4); P0 = digit_table[4];break;
		case '6':digit_select(5); P0 = digit_table[5];break;
		case '7':digit_select(6); P0 = digit_table[6];break;
		case '8':digit_select(7); P0 = digit_table[7];break;
		default:P0 = 0xff;
	}

}


void main(void)
{
#if 1		
	SCON = 0x50;			
	TMOD &= 0x0F;		
	TMOD |= 0x20;		
	TL1 = 0xFD;	
	TH1 = 0xFD;		
	ES = 1;
	EA = 1;		
	TR1 = 1;
#endif
	//P0 = 0xEF;	
	while(1);
		
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值