NO9 蓝桥杯单片机串口通信之进阶版

1 回顾

串口通信的代码编写结构还是与中断一样,不同的是:

初始中断函数条件涉及到串口通信相关的寄存器和定时器1相关的寄存器(定时器1用于产生波特率),但初始条件中的中断寄存器只考虑串口通信而不考虑定时器1。

void  函数名()

{

包含两部分寄存器:定时器1+串口通信

定时器1: TMOD (选择模式),TH1和TL1(初始计时寄存器),TR1(TCON寄存器里的启动计时按钮)

串口通信:SCON(总的来说功能是模式选择),AUXR(辅助寄存器),中断开关(分开关+总开关)

}

void  函数名() interrupt  中断号

{

就是写时间到后执行什么。注意中断号要写串口通信的,而不是定时器的,因为定时器作用只是产生波特率而不是产生中断。

}

2 C语言字符串知识补充:

字符串的C语言知识发现自己还不是很懂,就简单写一下。

常用的有两种,一种是字符串常量,一种是字符串数组。

判断字符串中止的标志是“\0 ”,表示NULL。

2.1 字符串常量

公式:char  *(+指针名称如A)= “ 字符串常量内容”

表示在A指针所对应的往下连续地址中,储存字符串常量。

char *message = "Hello World!";

// 上面的语句也可以拆分成下面两句
char *message;
message = "Hello World!";

2.2 字符串数组

char charArray[] = {'H','e','l','l','o'};    // 声明并初始化一个字符数组
char charArray[] = "Hello World!"; 

以上参考以下帖子,详情可点击进去查看。

C语言 -- 字符串详解 - 知乎 (zhihu.com)

3 实践

3.1 任务

3.2 思路

读题目是串口通信———那么就要写串口通信的结构

采用8位UART模式,波特率9600--------这些条件就可以确定串口通信结构的中断初始函数怎么写(NO9串口通信实践的另一篇有详细说明这里就不再赘述)

void Init_uart()
{
  TMOD = 0x20;
  TH1 = 0xfd;
  TL1 = 0xfd;
  TR1 = 1;
  
  AUXR = 0x00;
  
  SCON = 0x50;
  ES = 1;
  EA = 1;
  
}

要上上位机发送,故要写一个发送函数,又是字符串,那么就要利用2的字符串知识补充来写

这里字符串是一个字符接一个字符来发的(但速度较快看起来就是一下子发了出来),而 while(*str != '\0') 是判断字符串是否发完了,如果没发完,那么字符串的指针就加1,即一个一个字节来发。

void SentByte(unsigned char dat)
{
  SBUF = dat;
  while(TI == 0);
  TI = 0;
}

void SentString(unsigned char *str)
{

    while(*str != '\0')
    {
       SentByte(*str++);
    }

}

通过串口发送的接收命令来进行控制操作,那么就需要一个收的操作,并且还要写一个函数来判断并执行不同命令。

这里就主要将以下这个判断命令的思路。

命令分三种,是0xa_ , 0xb_ ,和0xc0,a,b,c来判断哪一种命令,低四位则代表这种命令的相关操作。

首先就要区别abc哪一种命令,这里可以用command来储存收到的命令,用command & 0xf0 来判断是a还是b还是c,与上0xf0,即是保留command高四位去掉低四位,那么command要么是0xa0要么是0xb0要么是0xc0,然后再用一个switch-case来存放三种命令的情况。

case里面放置三种命令的具体执行。

case(0xa0):是要用command的低四位去控制灯(L1~L4),注意这里1是开灯,0是关灯。(而单片机本身是0才亮灯。)

这里用这个公式来执行此命令: P0 = ~(command & 0x0f);  break;

分析:command先与上0x0f,表示command高四位清零,低四位保留,然后在取反。

比如 command = 0xa3(1010 0011),表示L1和L2点亮。

1010 0011   

                    & 

0000 1111

                     =

0000 0011

然后~(0000 0011) = 1111 1100, 而在单片机上恰好和命令相反是0时灯才亮,所以就完成了。

(注意,判断哪种命令时使用了command&0xf0,并没有改变command的值,因为它是在switch条件里的switch(command & 0xf0)的操作,而不是command = command &0xf0,所以这里并没有改变command的值。)

case(0xb0):这里就不再解释0xb0了,和0xa0的操作思路差不多。

case(0xc0):此命令是发送字符串,那么就用到了写的sentByte函数,注意这里发送完后command要清零,不然就会循环发送字符串。

unsigned char dat;
unsigned char command = 0x00;
void Service_uart() interrupt 4
{
  if (RI == 1)       收操作
  {
    command = SBUF;
    RI =0;
  }
  
}


void Working()      判断并执行命令
{
  if(command != 0x00)
  {
    switch(command & 0xf0)
    {
      case(0xa0):
        P0 = ~(command & 0x0f);  break;
      case(0xb0):
        P0 = ~((command & 0x0f)<<4);  break;
      case(0xc0):
        SentString("The system is running...\n"); command = 0x00; break;    
        
    }
  }
}

3.3 完整代码

#include "stc15f2k60s2.h"




void selectHC138(unsigned int n)
{
  switch(n)
  {
    case 0:
      P2 = (P2 & 0x1f) | 0x00;  break;
    case 1:
      P2 = (P2 & 0x1f) | 0x20;  break;
		case 2:
			P2 = (P2 & 0x1f) | 0x40;  break; 
		case 3: 
			P2 = (P2 & 0x1f) | 0x60;  break; 
		case 4:
			P2 = (P2 & 0x1f) | 0x80;  break; 
		case 5:
			P2 = (P2 & 0x1f) | 0xa0;  break; 
		case 6:
			P2 = (P2 & 0x1f) | 0xc0;  break; 
		case 7:
			P2 = (P2 & 0x1f) | 0xe0;  break;
  }
}
//==================================
void Init_uart()
{
  TMOD = 0x20;
  TH1 = 0xfd;
  TL1 = 0xfd;
  TR1 = 1;
  
  AUXR = 0x00;
  
  SCON = 0x50;
  ES = 1;
  EA = 1;
  
}

unsigned char dat;
unsigned char command = 0x00;
void Service_uart() interrupt 4
{
  if (RI == 1)
  {
    command = SBUF;
    RI =0;
  }
  
}


void SentByte(unsigned char dat)
{
  SBUF = dat;
  while(TI == 0);
  TI = 0;
}

void SentString(unsigned char *str)
{

    while(*str != '\0')
    {
       SentByte(*str++);
    }

}


void Working()
{
  if(command != 0x00)
  {
    switch(command & 0xf0)
    {
      case(0xa0):
        P0 = ~(command & 0x0f);  break;
      case(0xb0):
        P0 = ~((command & 0x0f)<<4);  break;
      case(0xc0):
        SentString("The system is running...\n"); command = 0x00; break;    
        
    }
  }
}


//===============================


void close()
{
  selectHC138(5);
  P0 = 0x00;
  selectHC138(4);
  P0 = 0xff;
}

void main()
{
  close();
  Init_uart();
  SentString("Welcome to system!\n");
  while(1)
  {
    Working();
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/485653.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python学习(一)

Python环境下载安装 安装略 验证安装结果与编写第一个Python程序

MySQL学习笔记------SQL(1)

关系型数据库&#xff08;RDBMS&#xff09; 建立在关系模型基础上&#xff0c;由多张相互连接的二维表组成的数据库 特点&#xff1a;使用表储存数据&#xff0c;格式统一&#xff0c;便于维护 使用SQL语言操作&#xff0c;标准统一&#xff0c;使用方便 SQL通用语法 SQL…

【Java】this 与 super 关键字

目录 this 关键字基本使用 this关键字在继承中的使用 super关键字使用 super 和 this 的比较 this 关键字基本使用 this 关键字可以用来访问本类的属性、方法、构造器 this 用于区分当前类的属性和局部变量&#xff0c;this代表当前对象访问成员方法的语法&#xff1a;thi…

Kruskal最小生成树【详细解释+动图图解】【sort中的cmp函数】 【例题:洛谷P3366 【模板】最小生成树】

文章目录 Kruskal算法简介Kruskal算法前置知识sort 中的cmp函数 算法思考样例详细示范与解释kruskal模版code↓ 例题&#xff1a;洛谷P3366 【模板】最小生成树code↓完结撒花QWQ Kruskal算法简介 K r u s k a l Kruskal Kruskal 是基于贪心算法的 M S T MST MST 算法&#xff…

Vue 实现带拖动功能的时间轴

1.效果图 2. 当使用timeline-slider-vue组件时&#xff0c;你可以设置以下属性&#xff1a; date&#xff1a;用于设置时间轴滑块的初始日期&#xff0c;格式通常为 YYYY-MM-DD。 mask&#xff1a;一个布尔值&#xff0c;用于控制是否显示背景遮罩。 markDate&#xff1a;一…

Verilog刷题笔记45

题目&#xff1a;Given the finite state machine circuit as shown, assume that the D flip-flops are initially reset to zero before the machine begins. Build this circuit. 解题&#xff1a; module top_module (input clk,input x,output z ); wire [2:0]size;dtou…

台灯学生用多少瓦的灯泡比较好?学生适用的五款护眼台灯推荐!

对于广大学生而言&#xff0c;选择一款合适的台灯灯泡瓦数至关重要。合适的瓦数不仅能够确保充足而均匀的照明&#xff0c;避免眼睛疲劳&#xff0c;还能在一定程度上节省能源。那么&#xff0c;台灯学生用多少瓦的灯泡比较好呢&#xff1f;今天就给大家科普一下&#xff0c;顺…

matlab实现遗传算法与蚁群算法

一、要求 1.利用matlab实现遗传算法和蚁群算法&#xff0c;解决相关问题 2.体会两种算法的具体作用 二、原理 &#xff08;1&#xff09;遗传算法&#xff1a; 不断循环&#xff0c;直到寻找出一个解 1. 检查每个染色体&#xff0c;看它解决问题的性能怎样&#xff0c;并…

C# for/foreach 循环

一个 for 循环是一个允许您编写一个执行特定次数的循环的重复控制结构。 语法 C# 中 for 循环的语法&#xff1a; for ( init; condition; increment ) {statement(s); } 下面是 for 循环的控制流&#xff1a; init 会首先被执行&#xff0c;且只会执行一次。这一步允许您声…

【协议-HTTPS】

https https是在http协议的基础上&#xff0c;添加了SSL/TLS握手以及数据加密传输&#xff0c;也属于应用层协议。 httpshttp加密认证完整性保护 https交互图&#xff1a; HTTPS的整体过程分为证书验证和数据传输阶段&#xff1a; ① 证书验证阶段 浏览器发起 HTTPS 请求 服务…

Verilog刷题笔记44

题目&#xff1a;Consider the n-bit shift register circuit shown below: 解题&#xff1a; module top_module (input clk,input w, R, E, L,output Q );always(posedge clk)beginif(L1)Q<R;elseQ<(E1)?w:Q;endendmodule结果正确&#xff1a; 注意点&#xff1a; …

Web实现名言生成器:JavaScript DOM基础与实例教程

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

iscsi网络协议(连接硬件设备)

iscsi概念 iscsi是一种互联网协议&#xff0c;用于将存储设备&#xff08;如硬盘驱动器或磁带驱动器&#xff09;通过网络连接到计算机。它是一种存储区域网络&#xff08;SAN&#xff09;技术&#xff0c;允许服务器通过网络连接到存储设备&#xff0c;就像它们是本地设备一样…

Godot 学习笔记(4):一切以场景为中心

文章目录 前言场景搭建新建子场景最简单的按钮事件 手动控制场景手动加载场景添加多个场景对象更快速的获取脚本对象 删除多个场景对象脚本命名的问题 总结 前言 Godot的场景是C#与Godot最后的中间连接。我们解决了场景的加载&#xff0c;我们基本可以保证C#和godot之间的彻底…

springcloud第4季 负载均衡的介绍3

一 loadbalance 1.1 负载均衡的介绍 使用注解loadbalance&#xff0c;是一个客户端的负载均衡器&#xff1b;通过之前已经从注册中心拉取缓存到本地的服务列表中&#xff0c;获取服务进行轮询负载请求服务列表中的数据。 轮询原理 1.2 loadbalance工作流程 loadBalance工作…

Uni-App电商模板,纯前端模板,可直接使用 实现全平台适配与高效功能

一、引言 随着移动互联网的快速发展&#xff0c;多平台应用开发已成为业界关注的焦点。Uni-App&#xff0c;作为一种前端框架&#xff0c;可以实现一套代码多端运行&#xff0c;大大提高了开发效率。本文将介绍如何使用Uni-App搭建一个电商模板&#xff0c;实现全平台适配与高…

WSL下Ubuntu+RTX4090安装CUDA+cuDnn+Pytorch

安装驱动 首先需要明确的是&#xff0c;在WSL下安装Ubuntu&#xff0c;如果要使用主机的GPU卡&#xff0c;只需要在主机Windows上安装驱动&#xff0c;Linux中不需要安装驱动&#xff0c;可以在Linux中使用nvidia-smi命令查看驱动版本。 安装CUDA 避坑注意事项&#xff1a;如…

机器学习(27)

文章目录 文献阅读1. 题目2. abstract3. 网络架构3.1 Theoretical Results 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 数据集4.3.2 参数设置 4.4 结论 三、实现GAN1. 任务要求2. 实验结果3.实验代码3.1数据准备3.2 模型构建3.3 展示函数3.4 训练过程 小结本周内…

循环队列、循环队列的基本操作

我要成为嵌入式高手之3月22日数据结构第五天&#xff01;&#xff01; ———————————————————————————— 顺序队列 存在问题&#xff1a;假溢出——解决办法&#xff1a;循环队列 空队列、满队列如何判断&#xff1f; 满队列&#xff1a;rear 1 …

一图详解 UVM phase机制

UVM验证环境构建时&#xff0c;引入 phase机制 &#xff0c;通过该机制可以很清晰的 将UVM仿真阶段层次化 。这里层次化&#xff0c;不仅仅是 各个phase的执行顺序 &#xff0c;还有 同一phase中的层次化组件之间phase也有先后关系 。 phase函数/任务执行顺序功能典型应用buil…