蓝桥杯单片机
或非门(英语:NOR gate)是一种基本的逻辑门电路,当它的两个输入同时为低电平时,输出为高电平;当任一输入为高电平时,输出为低电平。或非门的符号是"|",或非门的真值表如下:
输入A | 输入B | 输出 |
---|---|---|
0 | 0 | 1 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 0 |
或非门在数字电路设计中有广泛的应用,例如在组合逻辑电路中,可以用来实现逻辑函数的计算。
1T和12T指的是时钟周期和机器周期之间的关系,机器周期=(1/时钟频率 )* T模式
在1T模式下,系统外部时钟为12MHz晶振工作的12分频,每个系统周期就是1us
Led底层
void Led_Show(unsigned char addr,flag)
{
static unsigned char temp = 0x00;
static unsigned char temp_old = 0xff;
if(flag)
temp |= 0x01<<addr;
else
temp &= ~(0x01<<addr);
if(temp != temp_old)
{
P0 = ~temp;
P2 = P2 & 0x1f | 0x80;
P2 &= 0x1f;
temp_old = temp;
}
}
数码管
数码管展示函数代码
unsigned char Nixie_num[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x88};
unsigned char Nixie_wei[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned char Nixie_Show(unsigned char wei,num,point)
{
//消影操作
P0 = 0xff;
P2 = P2&0x1f|0xe0;
P2 &= 0x1f;//关闭锁存器
//数码管位选
P0 = Nixie_wei[wei];
P2 = P2&0x1f | 0xc0;
P2 &= 0x1f;//关闭锁存器
//数码管段选
P0 = Nixie_num[num];
if(point)
P0 &= 0x7f;//如果有小数点则加上小数点
P2 = P2&0x1f|0xe0;
P2 &= 0x1f;//关闭锁存器
}
位选通道
将锁存器HC573的Y6端口打开P2 = (P2 &0x1f)| 0xc0;
八位数码管分别是 0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80
段选通道
将锁存器HC573的Y7端口打开 P2 = (P2&0x1f)|0xe0;
DS18B20
第一步:初始化DS18B20
第二步:跳过ROM指令(Skip Rom)0xCC
第三步:执行温度转换(CONVERT)0x44
再次初始化,再次跳过ROM,执行读取暂存器(READ SCRATCHPAD)0xbe
(high<<8)|low/精度
float Read_T()
{
unsigned char TH,TL;
DS18B20_Init();
DS18B20_SendByte(0xCC);//发送跳过rom指令
DS18B20_SendByte(0x44);//执行温度转换命令
DS18B20_Init();//再次初始化
DS18B20_SendByte(0xCC);//发送跳过ROM指令
DS18B20_SendByte(0xbe);//执行读取暂存器指令
TL = DS18B20_ReadByte();//先读低字节
TH = DS18B20_ReadByte();
return ((TH<<8)|TL)/16.0;
}
//设置精度可以不用记
#define DS18B20_RESOLUTION_12 0x7F //精度为0.0625 750ms该时间为最大转换时间
#define DS18B20_RESOLUTION_11 0x5F //精度为0.125 375ms
#define DS18B20_RESOLUTION_10 0x3F //精度为0.25 187.5ms
#define DS18B20_RESOLUTION_9 0x1F //精度为0.5 93.75ms
void DS18B20_WriteByte(unsigned char Command)
{//DS18B20执行写入暂存寄存器指令
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_WRITE_SCRATCHPAD);
OneWire_SendByte(0x7F);//写入第一个字节为TH
OneWire_SendByte(0x00);//写入第二个字节为TL
OneWire_SendByte(Command);//写入第三个字节为分辨率,即精度
}
NE555
采用定时器T0做计数器时,将P34引脚和signal连接可捕获脉冲;采用T1做计数器时,需要将P35引脚连接signal。
#include <STC15F2K60S2.H>
unsigned int freq;
unsigned int time_1s;
// 计数器0
void Timer0Init(void) // 0微秒@12.000MHz
{
AUXR &= 0x7F; // 定时器时钟12T模式
TMOD &= 0xF0; // 设置定时器模式
TMOD |= 0x05;//不自动重装 0101 后两位01表示16位不自动重装载模式 第三位置1做计数器,置0做定时器
TL0 = 0x00; // 设置定时初值
TH0 = 0x00; // 设置定时初值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
}
// 定时器1
void Timer1Init(void) // 1毫秒@12.000MHz
{
AUXR &= 0xBF; // 定时器时钟12T模式
TMOD &= 0x0F; // 设置定时器模式
TL1 = 0x18; // 设置定时初值
TH1 = 0xFC; // 设置定时初值
TF1 = 0; // 清除TF1标志
TR1 = 1; // 定时器1开始计时
ET1 = 1; // 允许定时器1中断
EA = 1; // 允许总中断
}
void Timer1Sever() interrupt 3
{
if (++time_1s == 1000)
{
time_1s = 0;
// 1秒定时器中断
freq = TH0 << 8 | TL0; // 读取计数器0当前值
TH0 = 0;
TL0 = 0;
}
}
void main()
{
}
超声波
sbit Tx = P1^0;
sbit RX = P1^1;
void wave_init()
{
unsigned char i;
for(i = 0;i<8;i++)
{//发送8个方波
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
unsigned int ut_wave_data()
{
unsigned int time;
TMOD &= 0x0f;//不影响定时器0 使用定时器1
TH1 = TL1 = 0;//清空计数
wave_init();//发送方波
TR1 = 1;//定时器1开始计时
while((RX == 1) && (TF1 == 0));//定时器没有溢出,并且也没有收到值,则卡住
TR1 = 0;//停止计时
if(TF1 == 0)
{//如果没有溢出,则表示正常收到信号
time = TH1<<8 | TL1;
return (time*0.017);
}
else
{//如果溢出,清除溢出标志位
TF1 = 0;
return 0;
}
}
sbit Tx = P1^0;
sbit RX = P1^1;
void Delay12us(void) //@12.000MHz
{
unsigned char data i;
_nop_();
_nop_();
i = 38;
while (--i);
}
void wave_init()
{
unsigned char i;
for(i = 0;i<8;i++)
{//发送8个方波
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
unsigned int ut_wave_data()
{
unsigned int time;
CH = CL = 0;//清空PCA寄存器计数值
CMOD = 0x00;//初始化PCA寄存器
EA = 0;//关闭总中断
wave_init();//发送方波
EA = 1;//打开总中断
CR = 1;//PCA开始计数
while((RX == 1) && (CF == 0));//RX=1说明一直没有收到信号;CF = 0说明没有溢出
CR = 0;//PCA停止计数
if(CF == 0)
{//如果没有溢出,则表示正常收到信号
time = CH<<8 | CL;
return (time*0.017);
}
else
{//如果溢出,清除溢出标志位
CF = 0;
return 0;
}
}
IIC
PCF8591
//AD:模拟(外设)(电压)->数字(计算机)
//AIN0: 右边排针 channel 0 0x00
//AIN1: 光敏电阻 channel 1 0x01
//AIN2: 放大器 channel 2 0x02
//AIN3: 滑动变阻器channel 3 0x03
u00;
IIC_SendByte(0x91);
IIC_WaitAck();
temp = IIC_ReceiveByte();
IIC_SendAck(1);
IIC_Stop();
return temp;
}
void Write_DA(unsigned char data)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x41);//使能转换0x41 0x43皆可以
IIC_WaitAck();
IIC_SendByte(data);
IIC_WaitAck();
IIC_Stop();
}
EEPROM
AT24C02有32页,每页可以存储8个字节;如果在同一页内容超过了8个字节,则会覆盖先前的字节
//p是要写入的数据的地址 address是写入EEPROM中的地址 size 是要写入的大小
void EEPROM_Write(unsigned char *p,address,size)
{
IIC_Start();
IIC_SendByte(0xA0);//选择EEPROM 写模式
IIC_WaitAck();
IIC_SendByte(address);//发送要写入的地址
IIC_WaitAck();
while(size--)
{
IIC_SendByte(*p++);//*为解引用,即取出该地址中的内容 ++表示执行完后数组地址加一位
IIC_WaitAck();
IIC_Delay(200);
}
IIC_Stop();
}
void EEPROM_Read(unsigned char *p,address,num)
{
IIC_Start();
IIC_SendByte(0xA0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IICSendByte(0xA1);
IIC_WaitAck();
While(num--)
{
*p++ = IICReceiveByte();
if(num) IICSendAck(0);//如果还有数据,发送应答0
else IIC_SendAck(1);//如果无数据,不应答
}
IIC_Stop();
}
串口
在<stdio.h>的头文件中,函数sprintf(uart_send,“T = %f”,T);
Sprintf 可以将一个整数或其他想添加到字符串的数添加到字符串,注意unsigned char 型的值-48后才是正常数字,亦或者将其转换为unsigned int 型,用%d占位
void Uart1_Init(void) //9600bps@12.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0xE6; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
ES = 1; //打开串口中断
EA = 1; //打开总中断
}
void SendByte(unsigned char dat)
{
SBUF = dat;//将数据赋给SBUF,将数据发出
while(TI == 0);//等待数据发送
TI = 0;//将发送标志位清零
}
void Uart_Send_String(unsigned char *dat)
{
while(*dat != '\0')//当字符不为空是继续发送
SendByte(*dat++);//取出data数组的第一个后接着取下一个,直到读取到\0
}
串口接受电脑数据时要记得将指针清零
void Uart_Pro()
{
if(Uart_Slow_Down) return;
Uart_Slow_Down = 1;
if(Uart_Recv_Index > "size") //如果要发送索引大于字符串长度,清零
Uart_Recv_Index = 0;
if(Uart_Rec_Index == 1)//接收一个字符的数据
{
if(Uart_Rec[0] == 'a')
{
//执行相应操作
}
Uart_Rec_Index = 0;//将索引清零
}
}
void Uart1_Routine() interrupt 4
{
if(RI == 1 && Uart_Recv_Index < "size")// 串口接受数据
{
Uart_Recv[Uart_Recv_Index] = SBUF;//将SBUF区的数据赋给uart接受数组
Uart_Recv_Index++;//数组索引++
RI = 0;
}
}
串口所用引脚P30 和 P31 TX = P3^1,RX = P3^0,
在使用时可能会遇到无法发送的问题,可以查看是否用到了P30,P31这两个引脚;
记得打开中断ES= 1;EA= 1;
extern char putchar(char ch)
{
SBUF = ch;//将要发送的数据给SBUF
while(TI == 0);//等待数据发送
TI = 0;//将发送标志位清零
return (ch);
}
/*发送的时候*/
printf("%d",s);//直接打印
进阶矩阵键盘
unsigned int Key_Read()
{
unsigned int temp = 0;//16bit对应16个按键
int row, col;
for(col=0;col<4;col++)
{
P44 = (col != 0);
P42 = (col != 1);
P35 = (col != 2);
P34 = (col != 3);
for(row=0;row<4;row++)
{
if (!(P3&(0x08>>row))) //第0行-P33 第1行-P32 第2行-P31 第3行-P30 顺序相反
temp |= (1 << ( col* 4 + row ));
}
}
return temp;
}
//main函数
#define Key_Num(i) 0x0001 << (i-4)
#define KeyDown_Num(i) Key_Down & Key_Num(i)
#define KeyUp_Num(i) Key_Up & Key_Num(i)
void Key_Proc()
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;
Key_Val = Key_Read();
Key_Down = Key_Val & (Key_Old ^ Key_Val);
Key_Up = ~Key_Val & (Key_Old ^ Key_Val);
Key_Old = Key_Val;
if(KeyDown_Num(4))
{
if(!KeyDown_Num(9)) //排除组合按键
{
//S4单按键功能区
}
}
if(KeyDown_Num(9)) //按键S9产生下降沿
{
if(!KeyDown_Num(4)) //排除组合按键
{
//S9单按键功能区
}
}
if((KeyDown_Num(4)) && (KeyDown_Num(9)))
{
//S4+S9组合按键功能区
}
}
l);
Key_Up = ~Key_Val & (Key_Old ^ Key_Val);
Key_Old = Key_Val;
if(KeyDown_Num(4))
{
if(!KeyDown_Num(9)) //排除组合按键
{
//S4单按键功能区
}
}
if(KeyDown_Num(9)) //按键S9产生下降沿
{
if(!KeyDown_Num(4)) //排除组合按键
{
//S9单按键功能区
}
}
if((KeyDown_Num(4)) && (KeyDown_Num(9)))
{
//S4+S9组合按键功能区
}
}
[外链图片转存中...(img-0Cv6uT9x-1723276501455)]
[外链图片转存中...(img-M58SmT1W-1723276501456)]