学习总结(4_8-4_15)

一,单片机

单片机学习总结出了一个重要经验:程序的编写以实现需以A2开发板原理图和相关元器件的手册为基础来编写

  1. 矩阵按键
    电路图在这里插入图片描述
    工作原理
    若我们想选中第一个S1,则先令P1为0xFF(1111 1111),使所有都设置为高电平,然后使P17为0,即可选中1,若我们想让S1输出为1,则创建一个unsigned char Key函数,返回值为1即可,其他按键同理
#include <STC89C5xRC.H>
#include "Delay.h"
 
unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P13=0;
	if(P17==0){Delay(20);while(P17==0);Delay(20);KeyNumber=1;}
	if(P16==0){Delay(20);while(P16==0);Delay(20);KeyNumber=5;}
	if(P15==0){Delay(20);while(P15==0);Delay(20);KeyNumber=9;}
	if(P14==0){Delay(20);while(P14==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
	P12=0;
	if(P17==0){Delay(20);while(P17==0);Delay(20);KeyNumber=2;}
	if(P16==0){Delay(20);while(P16==0);Delay(20);KeyNumber=6;}
	if(P15==0){Delay(20);while(P15==0);Delay(20);KeyNumber=10;}
	if(P14==0){Delay(20);while(P14==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
	P11=0;
	if(P17==0){Delay(20);while(P17==0);Delay(20);KeyNumber=3;}
	if(P16==0){Delay(20);while(P16==0);Delay(20);KeyNumber=7;}
	if(P15==0){Delay(20);while(P15==0);Delay(20);KeyNumber=11;}
	if(P14==0){Delay(20);while(P14==0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;
	P10=0;
	if(P17==0){Delay(20);while(P17==0);Delay(20);KeyNumber=4;}
	if(P16==0){Delay(20);while(P16==0);Delay(20);KeyNumber=8;}
	if(P15==0){Delay(20);while(P15==0);Delay(20);KeyNumber=12;}
	if(P14==0){Delay(20);while(P14==0);Delay(20);KeyNumber=16;}
	
	return KeyNumber;
}

注意按键消抖
2. 定时器
介绍:定时器是单片机的内部资源,可提高cpu运行效率,也可在一定条件下替换Delay函数
51单片机有多个定时器,其中T0与T1(串口通信)常用
工作原理
单片机内部有一个类似闹钟的装置,每隔一段时间计数器加一,当达到一定值时则触发中断系统,中断当前的程序而执行定时器程序,例如一个学生在写作业被父母叫去吃饭。
在这里插入图片描述
在这里插入图片描述
我们可以按照此图来写定时器程序,以T0定时器为例,图二是控制定时器模式,高四位为T1定时器,低四位为T0定时器,我要启用T0定时器则给前面高四位置1,设置第四位即可,GATE不用设置置0即可,CT为0时为定时器模式,所以CT为0,M1和M2是设置定时器模式,定时器有多个模式,如十六位自动重载,十六位,八位自动重载等,而T0定时器十六位常用,M1 M0 = 01:方式1,是16位定时器/计数器。M1 M0 = 10:方式2,8位自动重装定时器/计数器。所以给M1为0,M2为1,CT为1时为计时器功能,CT为0时为定时器功能,所以应该给CT置0,根据图中TR0置1,TL0与TH0分别是设置低位设置定时初值和高位设置定时初值,如我要定时一毫秒使得计数器加一则令TL0 = 0x18,TH0 = 0xFC,也可以通过stc-isp里的定时计算器设置自己想要的值,如5ms加1,当定时器达到一定的值使TF0为1,执行中断程序,当中断程序完成时,记住使TF0置0,也意味着定时器初始化时也得置0,ET0,EA,PT0是设置是否要执行中断程序和中断优先级因此得出以下程序

#include <STC89C5xRC.H>
 
 
/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		
	TMOD |= 0x01;		
	TL0 = 0x18;		
	TH0 = 0xFC;		//1毫秒定时
	TF0 = 0;		
	TR0 = 1;	
	ET0=1;
	EA=1;
	PT0=0;
}
 

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;  
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}

  1. 串口通信
    串口有多个模式,如下图所示
    在这里插入图片描述
    工作原理
    在这里插入图片描述
    与前面定时器想类似,不过使用的是定时器T1,但一个个配置过于繁杂,我们可以借助stc-isp波特率计算器和串口助手配置相关模式,定时器配置也建议使用stc-isp以提高代码编写效率
    在这里插入图片描述
    结合stc-isp波特率计算器得出代码
#include <STC89C5xRC.H>
 
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON &= 0x80;		//波特率不倍速
	SCON = 0x40;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFA;		//设置定时初始值
	TH1 = 0xFA;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
}
 
void UART_SendByte(unsigned char Byte)
{
	SBUF=Byte;  // 根据硬件原理,操作寄存器
	while(TI==0);  // 操作寄存器,检测是否完成
	TI=0;  // 按要求重新赋值为0
}
  1. LED点阵屏
    工作原理
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    51单片机是88的点阵屏,相当于有88个小灯,根据图一可知,P0口是控制列,而D0-D7控制行,可与前面的矩阵按键相类比,有许多的相似性,但不同的是控制行的D0-D7口并非由P口控制,需借助74HC595,74HC595工作原理图参考图二,首先先传入一位到SER(P34),然后通过上升沿移位SERCLK(P36)送到上升沿锁存RCLK(P35)**(注意,送二进制位时需使SERCLK置1,然后再置0)**后推送到QA-D0,当D0为0时,第一行会亮,又因为其过程只能传入一位,所以得需要运用for循环把其余四位传入到D1-D7,代码如下
#include <STC89C5xRC.H>
#include "Delay.H"
 
sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;	//SER
 
#define MATRIX_LED_PORT  P0
 
void _74HC595_WriteByte(unsigned char Byte)
{

	unsigned char i;
	for(i=0;i<8;i++)
	{
		SER=Byte&(0x80>>i);
		SCK=1;
		SCK=0;
	}
		RCK=1;
		RCK=0;
}
 
void MatrixLED_ShowColumn(unsigned char Column, Data)
{
	_74HC595_WriteByte(Data);

	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);
	MATRIX_LED_PORT=0xFF;
	
}
 
void main()
{
	SCK=0;
	RCK=0;
	while(1)
	{

		MatrixLED_ShowColumn(0,0x80);
		MatrixLED_ShowColumn(1,0x40);
		MatrixLED_ShowColumn(2,0x20);
		MatrixLED_ShowColumn(3,0x10);
	}
}
  1. DS1302实时时钟
    介绍:DS1302是一种低功耗的实时时钟芯片
    工作原理
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    DS1302具体如何运行请主要参考图二和图三,根据图三可知有字节写入和字节读取两个重要功能,而写入到哪里或者读取哪里则需参考图二,图二包含着秒,时和年等相关地址,读的地址是写的地址加一,代码的编写最重要的是参考图三,可知想要写入或读取时间都得使CE置1(注意使用前初始化,即使CE置0,SCLK置0),然后从低位开始输入,和LED点阵屏一样,都是一位一位的传入,而依靠SCLK(P36),因此得使用for循环把八位全部写入或读取,写入完成后再使得CE置0即可,而秒的变化,时钟的变化不需编写,芯片会自己编写,而我们只需要靠写入数据来设置时钟开始时间,然后在读取数据得到实时时钟,注意,写入数据一般我们都是写入十进制,但该芯片写入得用BCD码,因此写入数据时应将十进制转化为BCD码,读数据时将BCD码转化为十进制即可,代码如下
#include <STC89C5xRC.H>
 
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
 
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
 
 
unsigned char DS1302_TIME[]={24,4,16,12,59,55,6};
 
void DS1302_Init(void)
{
	DS1302_CE=0;
	DS1302_SCLK=0;
}
 
void DS1302_WriteByte(unsigned char Command, Data)
{
	unsigned char i;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_CE=0; //完成一次操作,释放IO
}
 
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i,Data=0x00;
	Command|=0x01;  //
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;  //根据时序操作
		DS1302_SCLK=1;
	}
		for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;  //重复置1是去掉一个周期,为的是满足时序
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;
	DS1302_IO=0;  // 如果不加这一行,将显示全0
	return Data;
}
 
void DS1302_SetTime(void)
{
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_TIME[0]/10*16+DS1302_TIME[0]%10);
	DS1302_WriteByte(DS1302_MONTH,DS1302_TIME[1]/10*16+DS1302_TIME[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_TIME[2]/10*16+DS1302_TIME[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_TIME[3]/10*16+DS1302_TIME[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_TIME[4]/10*16+DS1302_TIME[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_TIME[5]/10*16+DS1302_TIME[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_TIME[6]/10*16+DS1302_TIME[6]%10);
	DS1302_WriteByte(DS1302_WP,0x00);
}
 
void DS1302_ReadTime(void)
{
	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_TIME[0]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_TIME[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_TIME[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_TIME[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_TIME[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_TIME[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_TIME[6]=Temp/16*10+Temp%16;
}
  1. 蜂鸣器
    介绍
    在这里插入图片描述

工作原理
在这里插入图片描述
51单片机是无源蜂鸣器,由P25控制蜂鸣器是否发出声音

二,数据结构(C)

单链表与双链表
学习经验:数据结构的学习建议结合win系统自带的画图工具,在画图工具中用框把链表节点表现出来,让人更容易理解其中的原理
何为链表,以画图工具来演示会方便理解,链表即每个节点都一一相连,可从第一个节点访问到最后一个节点,和数组很相似,但数组与链表在内存的储存有着很大的区别
数组:
连续存储:数组中的元素在内存中是连续存储的,也就是说,数组的所有元素在内存中是相邻的。
快速访问:由于数组的元素是连续存储的,因此可以通过索引快速访问任何一个元素,时间复杂度为 O(1)。
固定大小:数组的大小是固定的,在创建时需要指定大小,无法动态改变。
链表:
非连续存储:链表中的元素在内存中不是连续存储的,而是通过指针相互连接起来的。
动态大小:链表的大小可以动态增长或减小,因为每个节点只存储了指向下一个节点的指针,所以可以在运行时动态地分配内存。
遍历复杂度:在链表中,访问特定位置的元素需要从头开始遍历直到找到目标位置,所以访问的时间复杂度是 O(n),其中 n 是链表的长度。
插入和删除效率高:由于链表的节点可以动态分配和释放,插入和删除元素的效率较高,平均时间复杂度为 O(1)。在这里插入图片描述
头插法与尾插法(以画图工具演示)
头插法
在这里插入图片描述
尾插法
在这里插入图片描述

  1. 单链表与单循环链表
    (1)介绍
    单链表:
    单链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
    每个节点只有一个指针,指向下一个节点,最后一个节点的指针指向 NULL(空)。
    单循环链表:
    单循环链表是单链表的一种变体,其特点是最后一个节点的指针不指向 NULL,而是指向第一个节点,形成一个环形结构。
    单循环链表可以通过任何一个节点开始遍历整个链表,因为整个链表形成了一个循环。
    单循环链表可以用于模拟循环操作,例如循环队列等数据结构。
    (2)画图工具演示
    在这里插入图片描述

(3)相关代码实现(加减与遍历链表,加包括头插法与尾插法)
单链表

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0
typedef struct Node {
    int data;
    struct Node* next;
}Node;


Node* initList() {
    Node* L = (Node*)malloc(sizeof(Node));
    L -> data = 0;
    L -> next = NULL;
    return L;
}
void headInsert(Node* L, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = L->next;
    L -> next = node;
    L -> data ++;
}
void tailInsert(Node* L, int data) {
    Node* node = L;
    for(int i = 0; i < L -> data; i++) {
        node = node->next;
    }
    Node* n = (Node*)malloc(sizeof(Node));
    n -> data = data;
    n -> next = NULL;
    node -> next = n;
    L -> data ++;
}

int delete(Node* L, int data) {
    Node* preNode = L;
    Node* node = L -> next;
    while(node){
        if(node -> data == data) {
            preNode -> next = node->next;
            free(node);
            L -> data --;
            return TRUE;
        }
        preNode = node;
        node = node -> next;
    }
    return FALSE;
}

void printList(Node* L) {
    Node* node = L -> next;
    while(node){
        printf("node = %d\n", node -> data);
        node = node -> next;
    }
}


int main() {
    Node* L = initList();
    headInsert(L, 1);
    headInsert(L, 2);
    headInsert(L, 3);
    headInsert(L, 4);
    headInsert(L, 5);
    tailInsert(L, 6);
    tailInsert(L, 7);
    printList(L);

    if (delete(L, 3)) {
        printf("success delete\n");
    }
    else {
        printf("fail delete\n");
    }
    printList(L);
    return 0;
}

单循环链表

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

typedef struct Node {
    int data;
    struct Node* next;
}Node;

Node* initList() {
    Node* L = (Node*)malloc(sizeof(Node));
    L -> data = 0;
    L -> next = L;
    return L;
}

void headInsert(Node* L, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = L -> next;
    L -> next = node;
    L -> data ++;
}

void tailInsert(Node* L, int data) {
    Node* n = L;
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    while(n -> next != L){
        n = n -> next;
    }
    node -> next = L;
    n -> next = node;
    L -> data ++;
}

int delete(Node* L, int data) {
    Node* preNode = L;
    Node* node = L -> next;
    while(node != L){
        if(node -> data == data){
            preNode -> next = node -> next;
            free(node);
            L -> data --;
            return TRUE;
        }
        preNode = node;
        node = node -> next;
    }
    return FALSE;
}

void printList(Node* L) {
    Node* node = L -> next;
    while(node != L){
        printf("%d->", node -> data);
        node = node -> next;
    }
    printf("NULL\n");
}

int main()
{
    Node* L = initList();
    headInsert(L, 1);
    headInsert(L, 2);
    headInsert(L, 3);
    headInsert(L, 4);
    headInsert(L, 5);
    tailInsert(L, 6);
    tailInsert(L, 7);
    printList(L);
    delete(L, 4);
    delete(L, 7);
    printList(L);
    return 0;
}
  1. 双链表与双循环链表
    (1)介绍
    双链表:
    双链表中的每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。
    双链表可以实现双向遍历,可以从前向后或从后向前遍历链表。
    双链表的插入和删除操作相对于单链表来说更灵活,因为可以直接通过前向指针或后向指针找到相邻节点。
    双链表的缺点是每个节点需要额外的一个指针,占用的内存空间相对更多。
    双循环链表:
    双循环链表是双链表的一种变体,其特点是第一个节点的前向指针指向最后一个节点,最后一个节点的后向指针指向第一个节点,形成一个循环结构。
    双循环链表可以通过任何一个节点开始遍历整个链表,因为整个链表形成了一个循环。
    双循环链表适用于需要循环操作的场景,例如循环队列等。
    (2)画图工具演示
    双链表
    在这里插入图片描述
    双循环链表
    在这里插入图片描述
    (3)代码实现
    双链表
#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

typedef struct Node {
    int data;
    struct Node* pre;
    struct Node* next;
}Node;

Node* initList() {
    Node* L = (Node*)malloc(sizeof(Node));
    L -> data = 0;
    L -> pre = NULL;
    L -> next = NULL;
    return L;
}

void headInsert(Node* L, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = L -> next;
    node -> pre = L;
    if (L -> next) {
        L -> next -> pre = node;
        L -> next = node;
    }
    else {
        L -> next = node;
    }
}

void tailInsert(Node* L, int data) {
    Node* node = L;
    Node* n = (Node*)malloc(sizeof(Node));
    n -> data = data;
    while (node -> next) {
        node = node -> next;
    }
    n -> next = node -> next;
    node -> next = n;
    n -> pre = node;
    L -> data ++;
}

int delete(Node* L, int data) {
    Node* node = L->next;
    while (node) {
        if (node -> data == data) {
            node -> pre -> next = node -> next;
            if (node -> next) {
                node -> next -> pre = node -> pre;
            }
            L -> data --;
            free(node);
            return TRUE;
        }
        node = node -> next;
    }
    return FALSE;
}

void printList(Node* L) {
    Node* node = L -> next;
    while (node) {
        printf("%d -> ", node -> data);
        node = node -> next;
    }
    printf("NULL\n");
}

int main()
{
    Node* L = initList();
    headInsert(L, 1);
    headInsert(L, 2);
    headInsert(L, 3);
    headInsert(L, 4);
    tailInsert(L, 5);
    tailInsert(L, 6);
    printList(L);
    delete(L, 6);
    printList(L);
    return 0;
}

双循环链表

#include <stdio.h>
#include <stdlib.h>


typedef struct Node {
    int data;
    struct Node* pre;
    struct Node* next;
}Node;


Node* initList() {
    Node* L = (Node*)malloc(sizeof(Node));
    L -> data = 0;
    L -> pre = L;
    L -> next = L;
    return L;
}


void headInsert(Node* L, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = L -> next;
    node -> pre = L;
    L -> next -> pre = node;
    L -> next = node;
    L -> data ++;
}

void tailInsert(Node* L, int data) {
    Node* node = L;
    while (node->next != L) {
        node = node -> next;
    }
    Node* n = (Node*)malloc(sizeof(Node));
    n -> data = data;
    n -> pre = node;
    n -> next = L;
    L -> pre = n;
    node -> next = n;
    L -> data ++;
}

int delete(Node* L, int data) {
    Node* node = L -> next;
    while (node != L) {
        if (node -> data == data) {
            node -> pre -> next = node -> next;
            node -> next -> pre = node -> pre;
            free(node);
            L -> data --;
            return 1;
        }
        node = node -> next;
    }
    return 0;
}


void printList(Node* L){
    Node* node = L->next;
    while(node != L){
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

int main()
{
    Node* L = initList();
    headInsert(L, 1);
    headInsert(L, 2);
    headInsert(L, 4);
    headInsert(L, 5);
    printList(L);
    tailInsert(L, 6);
    tailInsert(L, 7);
    printList(L);
    delete(L, 7);
    printList(L);
    return 0;
}

三, C++

目前学到类和对象中的友元,以黑马教学视频为主,因在考虑单片机自己想实现的程序的实现与这几天课较多,暂不过多赘述,后面有时间补完

下周计划

  1. 51单片机基本要学完
  2. 学完c++类和对象
  3. 试试力扣算法题库并总结相关题目和学习经验
  4. 继续数据结构学习
  • 15
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值