精华内容
下载资源
问答
  • 学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好。Keil软件是目前最流行...学习之前请先安装KEILC51软件,在学会使用汇编语言后,学习C语言编程是一件比较容易的事,我们将通过一系列的实例介绍C语...

    学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好。Keil软件是目前最流行开发80C51系列单片机的软件,Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(?Vision)将这些部份组合在一起。

    学习之前请先安装KEILC51软件,在学会使用汇编语言后,学习C语言编程是一件比较容易的事,我们将通过一系列的实例介绍C语言编程的方法。图1-1所示电路图使用89c51单片机作为主芯片,这种单片机性属于80C51系列,其内部有8K的FLASH ROM,可以反复擦写,非常适于做实验。89c51的P1引脚上接8个发光二极管,P3.2~P3.4引脚上接4个按钮开关,我们的任务是让接在P1引脚上的发光二极管按要求发光。

    46560d8ec84ca9d7d9334b717703eb02.png


    1 简单的C程序介绍

    例1-1: 让接在P1.0引脚上的LED发光。

    /************************************************

    单灯闪烁程序

    *************************************************/

    #include "reg51.h"//这一句是将51的常用端口,内部寄存器等的定义文件包含进这段程序

    sbit P1_0=P1^0;

    void main()

    {  P1_1=0;

    }

    这个程序的作用是让接在P1.0引脚上的LED点亮。下面来分析一下这个C语言程序包含了哪些信息。

    1)"文件包含"处理。

    程序的第一行是一个"文件包含"处理。

    所谓"文件包含"是指一个文件将另外一个文件的内容全部包含进来,所以这里的程序虽然只有4行,但C编译器在处理的时候却要处理几十或几百行。这里程序中包含REG51.h文件的目的是为了要使用P1这个符号,即通知C编译器,程序中所写的P1是指80C51单片机的P1端口而不是其它变量。这是如何做到的呢?

    打开reg51.h可以看到这样的一些内容:

    /*--------------------------------------------------------------------REG51.H

    Header file for generic 80C51 and 80C31 microcontroller.

    Copyright (c) 1988-2001 Keil Elektronik GmbH and Keil Software, Inc.

    All rights reserved.

    --------------------------------------------------------------------------*/

    /* BYTE Register */

    sfr P0 = 0x80;

    sfr P1 = 0x90;

    sfr P2 = 0xA0;

    sfr P3 = 0xB0;

    sfr PSW = 0xD0;

    sfr ACC = 0xE0;

    sfr B = 0xF0;

    sfr SP = 0x81;

    sfr DPL = 0x82;

    sfr DPH = 0x83;

    sfr PCON = 0x87;

    sfr TCON = 0x88;

    sfr TMOD = 0x89;

    sfr TL0 = 0x8A;

    sfr TL1 = 0x8B;

    sfr TH0 = 0x8C;

    sfr TH1 = 0x8D;

    sfr IE = 0xA8;

    sfr IP = 0xB8;

    sfr SCON = 0x98;

    sfr SBUF = 0x99;

    /* BIT Register */

    /* PSW */

    sbit CY = 0xD7;

    sbit AC = 0xD6;

    sbit F0 = 0xD5;

    sbit RS1 = 0xD4;

    sbit RS0 = 0xD3;

    sbit OV = 0xD2;

    sbit P = 0xD0;

    /* TCON */

    sbit TF1 = 0x8F;

    sbit TR1 = 0x8E;

    sbit TF0 = 0x8D;

    sbit TR0 = 0x8C;

    sbit IE1 = 0x8B;

    sbit IT1 = 0x8A;

    sbit IE0 = 0x89;

    sbit IT0 = 0x88;

    /* IE */

    sbit EA = 0xAF;

    sbit ES = 0xAC;

    sbit ET1 = 0xAB;

    sbit EX1 = 0xAA;

    sbit ET0 = 0xA9;

    sbit EX0 = 0xA8;

    /* IP */

    sbit PS = 0xBC;

    sbit PT1 = 0xBB;

    sbit PX1 = 0xBA;

    sbit PT0 = 0xB9;

    sbit PX0 = 0xB8;

    /* P3 */

    sbit RD = 0xB7;

    sbit WR = 0xB6;

    sbit T1 = 0xB5;

    sbit T0 = 0xB4;

    sbit INT1 = 0xB3;

    sbit INT0 = 0xB2;

    sbit TXD = 0xB1;

    sbit RXD = 0xB0;

    /* SCON */

    sbit SM0 = 0x9F;

    sbit SM1 = 0x9E;

    sbit SM2 = 0x9D;

    sbit REN = 0x9C;

    sbit TB8 = 0x9B;

    sbit RB8 = 0x9A;

    sbit TI = 0x99;

    sbit RI = 0x98;

    熟悉80C51内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地址的对应关系。注意其中有

    sfr P1 = 0x90;

    这样的一行(上文中用黑体表示),即定义P1与地址0x90对应,P1口的地址就是0x90(0x90是C语言中十六进制数的写法,相当于汇编语言中写90H)。

    从这里还可以看到一个频繁出现的词:sfr

    sfr并标准C语言的关键字,而是Keil为能直接访问80C51中的SFR而提供了一个新的关键词,其用法是:

    sfrt 变量名=地址值。

    2)符号P1_0来表示P1.0引脚。

    在C语言里,如果直接写P1.0,C编译器并不能识别,而且P1.0也不是一个合法的C语言变量名,所以得给它另起一个名字,这里起的名为P1_0,可是P1_0是不是就是P1.0呢?你这么认为,C编译器可不这么认为,所以必须给它们建立联系,这里使用了Keil C的关键字sbit来定义,sbit的用法有三种:

    第一种方法:sbit 位变量名=地址值

    第二种方法:sbit 位变量名=SFR名称^变量位地址值

    第三种方法:sbit 位变量名=SFR地址值^变量位地址值

    如定义PSW中的OV可以用以下三种方法:

    sbit OV=0xd2 (1)说明:0xd2是OV的位地址值

    sbit OV=PSW^2 (2)说明:其中PSW必须先用sfr定义好

    sbit OV=0xD0^2 (3)说明:0xD0就是PSW的地址值

    因此这里用sfr P1_0=P1^0;就是定义用符号P1_0来表示P1.0引脚,如果你愿意也可以起P10一类的名字,只要下面程序中也随之更改就行了。

    3)main称为"主函数"。

    每一个C语言程序有且只有一个主函数,切必须有一个主函数,其放置的位置不要求,可以放在程序最后(推荐),函数后面一定有一对大括号"{}",在大括号里面书写其它程序。

    从上面的分析我们了解了部分C语言的特性,下面再看一个稍复杂一点的例子。

    例1-2 让接在P1.0引脚上的LED闪烁发光

    /*************************************************

    单灯闪烁程序

    *************************************************/

    #include "reg51.h"

    #define uchar unsigned char

    #define uint unsigned int

    sbit P10=P1^0;

    /*延时程序

    由Delay参数确定延迟时间

    */

    void mDelay(unsigned int Delay)

    { unsigned int i;

    for(;Delay>0;Delay--)

    { for(i=0;i<124;i++)

    {;}

    }

    }

    void main()

    { for(;;)

    { P10=!P10; //取反P1.0引脚

    mDelay(1000);

    }

    }

    程序分析:主程序main中的第一行暂且不看,第二行是"P1_0=!P1_0;",在P1_0前有一个符号"!",符号"!"是C语言的一个运算符,就像数学中的"+"、"-"一样,是一种运算任号,意义是"取反",即将该符号后面的那个变量的值取反。

    注意:取反运算只是对变量的值而言的,并不会自动改变变量本身。可以认为C编译器在处理"!P1_0"时,将P1_0的值给了一个临时变量,然后对这个临时变量取反,而不是直接对P1_0取反,因此取反完毕后还要使用赋值符号("=")将取反后的值再赋给P1_0,这样,如果原来P1.0是低电平(LED亮),那么取反后,P1.0就是高电平(LED灭),反之,如果P1.0是高电平,取反后,P1.0就是低电平,这条指令被反复地执行,接在P1.0上灯就会不断"亮"、"灭"。

    该条指令会被反复执行的关键就在于main中的第一行程序:for(;;),这里不对此作详细的介绍,读者暂时只要知道,这行程序连同其后的一对大括号"{}"构成了一个无限循环语句,该大括号内的语句会被反复执行。

    第三行程序是:"mDelay(1000);",这行程序的用途是延时1s时间,由于单片机执行指令的速度很快,如果不进行延时,灯亮之后马上就灭,灭了之后马上就亮,速度太快,人眼根本无法分辨。

    这里mDelay(1000)并不是由Keil C提供的库函数,即你不能在任何情况下写这样一行程序以实现延时。如果在编写其它程序时写上这么一行,会发现编译通不过。那么这里为什么又是正确的呢?注意观察,可以发现这个程序中有void mDelay(…)这样一行,可见,mDelay这个词是我们自己起的名字,并且为此编写了一些程序行,如果你的程序中没有这么一段程序行,那就不能使用mDelay(1000)了。有人脑子快,可能马上想到,我可不可以把这段程序也复制到我其它程序中,然后就可以用mDelay(1000)了呢?回答是,那当然就可以了。还有一点需要说明,mDelay这个名称是由编程者自己命名的,可自行更改,但一旦更改了名称,main()函数中的名字也要作相应的更改。

    mDelay后面有一个小括号,小括号里有数据(1000),这个1000被称之"参数",用它可以在一定范围内调整延时时间的长短,这里用1000来要求延时时间为1000毫秒,要做到这一点,必须由我们自己编写的mDelay那段程序决定的。

    嵌入式开发直播课 - c语言控制led灯 - 创客学院直播室www.makeru.com.cn
    15e38cb31d098658c9e823f66634a0f2.png

    https://jq.qq.com/?_wv=1027&k=LrSKKYES (二维码自动识别)

    展开全文
  • 阳极接高电平1,阴极接低电平0C语言(1)点亮第一个led1.引入头文件#include "reg52.h" 2.给ledd定义,定义为P2.0端口sbit led=P2^03.进入主函数使led=0,即P2.0接低电平,led发光(2)led闪烁1.先引入一个延时函数...

    82283e3892f5592329805157299a8603.png

    led原理

    将PN结用外壳封装起来,加上电极引线就构成了半导体二极管,由p区引出的电极为阳极,由N区引出的电极为阴极。

    9fdd21b63a8d02a8b8e7ad15bcfb3334.png
    阳极接高电平1,阴极接低电平0

    C语言

    (1)点亮第一个led

    1.引入头文件#include "reg52.h"

    2.给ledd定义,定义为P2.0端口sbit led=P2^0

    3.进入主函数使led=0,即P2.0接低电平,led发光

    (2)led闪烁

    1.先引入一个延时函数delay(给i赋值后,cpu连续执行运算i-1,所占用的时间表现为延迟)

    void 

    2.进入主函数后,引入while函数循环执行led=0,delay,led=1,delay。

    (3)led流水灯

    1.引入intrins头文件,#include<intrins.h>

    2.预定义led=P0

    3.进入主函数,先给led赋值led=0xfe//1111 1110,然后执行延时函数delay,然后进入移位延时函数

    for

    笔记

    1.while函数

    while循环的格式:while(表达式){语句;}

    while 循环的执行顺序:当表达式为真,则执行下面的语句,语句执行完之后再判断表达式是否为真,如果为真,再次执行下面的语句,然后再判断表达式是否为真……就这样一直循环下去,直到表达式为假,跳出循环。

    2.for函数

    for循环语句格式

    for(初始化语句;判断条件语句;控制条件语句) {循环体语句}

    1.执行初始化语句2.判断条件语句如果真就执行循环体语句,如果假,就结束跳出循环。3.执行控制条件语句4.回到2继续至到跳出循环

    3.sbit

    sbit 变量名=地址值;

    sbit led=P0^1;(P是大写)

    4.#define

    #define 宏名 字符串

    #define A P0(注意后面不用加分号)

    5.typedef

    typedef用来给变量类型取别名

    typedef unsigned int u16//u 16=unsigned int

    6.延时

    d93a1c21d509c7a0224e1f8037382105.png

    7.进制换算

    1.打开电脑自带的计算机(快捷方式window+r,然后输入calc)

    2.换成程序员模式

    3.HEX代表16进制, DEC代表10进制, OCT代表8进制, BIN代表2进制.

    d9089ef0a67cb5cd0d1eda215d8bb950.png

    8.instrins头文件

    025110cd4e2112fbd4353f095bda321f.png

    i=_crol_(i,1); /*将i循环左移1位*/

    i=_cror_(i,1); /*将i循环右移1位*/

    展开全文
  • 合金弹头https://www.zhihu.com/video/1217838581596786688分享17级同学大一上学期用C语言实现的合金弹头。分步骤代码、图片音乐素材、可执行程序可从百度网盘下载:链接:...

    65e56ba6fe9970ce2791c639fed0d62a.png
    5ae9f7596ab2d3815fa505890fccfa37.png
    合金弹头https://www.zhihu.com/video/1217838581596786688

    分享17级同学大一上学期用C语言实现的合金弹头。分步骤代码、图片音乐素材、可执行程序可从百度网盘下载:

    链接:https://pan.baidu.com/s/1cm01uEDNodXH-eU5zfF3kw

    提取码:toam

    一、设计思路

    1. 游戏主要基于Easyx提供的函数库,能够忽略WinAPI,减轻代码量。

    2. 游戏基本设计思路:

    为了方便总体控制和简化操作,选择将easyx底层抽象,可以直接加载相应动画图片到精灵(即游戏中的每个图像元素)结构,通过设置精灵结构中数据,来直接控制动画的播放和移动。

    为了实现精灵的操作,选择定义游戏图片结构,封装原图和蒙版,实现基本的根据坐标将蒙版和原图运算到背景中。

    为了方便精灵结构的管理,选择实现场景结构。场景主要负责根据Z轴顺序来绘制添加到该场景的所有精灵。另外可以将每个场景相应的逻辑函数,初始化函数,消息处理函数,关闭函数,储存在场景中方便调用。

    为了方便场景的管理,选择实现引擎结构。将场景添加到其中,设置相应的游戏编号。就可以通过游戏编号的转换实现场景的切换。

    游戏框架选择的基本循环框架。即包含游戏初始化,游戏主循环,消息处理,逻辑执行,碰撞检测,音乐控制。

    所有的添加都通过指针连接,最基本的图像结构通过new分配内存,每个结构提供释放函数

    3. 具体合金弹头的实现就可以通过,建立场景,建立精灵,将图片资源加载到精灵中。在需要的时候显示或者隐藏相应的动画。在逻辑中进行图片的移动判断,在相应的消息处理函数中,改变相应的变量。就可以完整的实现游戏的基本动画,和控制。具体细节,可以通过游戏的反馈进行调整.

    4. 具体的游戏资源收集于各论坛。

    5. 在最后对写好的游戏进行优化。

    二、功能描述

    1. 在主函数中依次调用,GameStart(),在主循环中调用MousEvent(),KeyEvent(),GameAction(),循环结束调用GameEnd();

    2. 游戏主体框架及功能

    typedef 

    3. 另外游戏通过在适当位置添加文件的读写操作(二进制),来实现基本的存档功能。

    三、分步骤实现的方法

    1. 主体框架的实现

    主题框架实现的重点主要在游戏精灵结构的实现以及各种播放模式的实现,要保证不冲突。还有就是游戏资源的释放,由于前期的设计问题,涉及到的多个相同精灵的复用,精灵结构中储存的是资源的地址,所以复用精灵使用的数组,添加到场景中,无法再使用delete来释放资源。具体解决方法,为每一个精灵增加了一个bool用来控制是否释放资源。

    2. 具体玩家人物的设计

    由于图像资源太过分开(分为上半身和下半身),导致人物的动作设计过于复杂,且代码可读性降低。同时由于相同动画资源图片大小不同导致必须每一帧的坐标都必须手动设置。具体解决办法,牺牲代码的可读性。

    3. 游戏音乐的实现

    在游戏中使用mciSendString()函数实现音乐的播放,但由于函数加载音乐资源速度太慢,会对游戏造成明显的卡顿。所以选择单独开一个线程来播放音乐。由于mciSendString使用的是栈操作,所以选择在线程函数中建立一个无限循环,通过不断的检测音乐标志的变化,来实现播放音乐。另外再降低音乐质量。

    四、体会与总结

    1. 版本控制很重要

    在游戏分步实现的过程中,随着编写的不断加深,代码量逐渐增大,每次修改都有可能会产生不可预料的结果。甚至有可能某个阶段功能的实现的失败。所以及时回溯,版本控制很重要。

    2. 前期设计的重要性

    最开始的设计关系到整个游戏最终是否能完成。不然就只能降低代码的可读性来实现。

    3. 团队

    一个人的精力是有限。在某些情况下需要多人合作。

    4. 总结

    这是我个人独立写过的代码最多行的程序(近4000行),代码写得越多对语言的设计理解的越深。这次的课设让我学到了很多。写代码的过程中遇到了很多的问题,设计不够完善,中途修改主体框架,找不到bug等等,但庆幸的是都一一解决掉(百度,参考手册,博客等).我以前也写过几个小程序,录频,合成图像,其中不乏一点原理也不懂的,但不懂的总是可以通过各种方法学会。所以不管写什么程序,不管有多复杂,只要坚持下去去学习研究尝试,总会写出来。另外整个框架的优势体现在有多个场景的游戏。

    展开全文
  • C语言用双引号描述一个字符串,如“abcd”。 下面我们通过一个实验来展示如何发送字符串。我们实验的目标是打印字符串“Hello World ! 第一!”到打印机。直接上代码。 [cpp] view plain copy#include "reg51.h"#...

    b91b90589644eac34b266460ba51517f.gif

    现实生活中, 我们总是要与人打交道,互通有无。和我们一样,单片机也需要跟各种设备做交互。例如汽车的显示仪表需要知道汽车的转速及电动机的运行参数,那么显示仪表就需要从汽车的底层控制器取得数据。而这个数据的获得过程就是一个通信过程。类似的例子还有控制器通常是单片机或者PLC与变频器的通信。通信的双方需要遵守一套既定的规则也称为协议,这就好比我们人之间的对话,需要在双方都遵守一套语言语法规则的基础上才有可能达成对话。


    通信协议又分为硬件层协议和软件层协议。硬件层协议主要规范了物理上的连线,传输电平信号及传输的秩序等硬件性质的内容。常用的硬件协议有串口,IIC, SPI, RS485, CAN和 USB。软件层协议则更侧重上层应用的规范,比如modbus协议。

    51单片机的串口通信协议

    下面我们就着重介绍51单片机的串口通信协议,以下简称串口。串口的6个特征如下。
    (1)、物理上的连线至少3根,分别是Tx数据发送线,Rx数据接收线,GND共用地线。

    (2)、0与1的约定。RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。TTL电平,约定5V的电压信号为1,0V电压信号为0 。CMOS电平,约定3.3V的电压信号为1,0V电压信号为0 。其中,CMOS电平一般用于ARM芯片中。

    (3)、发送秩序。低位先发。

    (4)、波特率。收发双方共同约定的一个数据位(0或1)在数据传输线上维持的时间。也可理解为每秒可以传输的位数。常用的波特率有300bit/s, 600bit/s, 2400bit/s, 4800bit/s, 9600bit/s。

    (5)、通信的起始信号。发送方在没有发送数据时,应该将Tx置1 。当需发送时,先将Tx置0,并且保持1位的时间。接受方不断地侦测Rx,如果发现Rx常时间变高后,突然被拉低(置为0),则视为发送方将要发送数据,迅速启动自己的定时器,从而保证了收发双方定时器同步定时。

    (6)、停止信号。发送方发送完最后一个有效位时,必须再将Tx保持1位的时间,即为停止位。

    a27bcc67ff636cc05ac80379d0e0065e.png

    理论暂时就先到这里,现在我们做一个实验,将一个字节从51单片机发送到电脑串口调试助手上。这个实验的目的是为了掌握串口通信协议的收发过程。

    虚拟串口试验

    实验一、虚拟串口实验

    一般单片机都有专门的串口引脚,51里面分别是P3.0和P3.1,这些引脚拥有串口的硬件电路,因此使用它们并不需要设置信号的发送停止。为了掌握协议,我们使用其他的引脚来模拟串口,所以也叫虚拟串口。这里我们选用P1.0,然而注意到我们51单片机要发送数据给电脑,必须经过一个串口转USB设备(即TTL电平转换为RS232电平),而限于我们的开发板只有P3.0与P3.1连接到了串口转USB设备,所以我们可以将P1.0短接到P3.1 。下图是这个串口转USB的原理图。

    97ddee9ce0e9d2b5aca0479c47e99b97.png

    好了直接上代码吧。

    [cpp] view plain copy#include "reg51.h"/*   将P1.0虚拟成串口发送脚TX   以9600bit/s的比特率向外发送数据   因为波特率是    9600bit/s  所以me发送一位的时间是 t=1000000us/9600=104us */sbit TX=P3^1; //P1^0 output TTL signal, need to transferred to rs232 signal, can be connected to P3^1  #define u16 unsigned int //宏定义  #define u8 unsigned char  u8 sbuf;  bit ti=0;  void delay(u16 x){  while(x--);  }  void Timer0_Init(){      TMOD |= 0x01;      TH0=65440/256;      TH0=65440%256;     TR0=0;  }  void Isr_Init(){      EA=1;      ET0=1;  }  void Send_Byte(u8 dat){  sbuf=dat;//通过引入全局变量sbuf,可以保存形参dat  TX=0; //A 起始位 TR0=1;  while(ti==0);    //等待发送完成  ti=0; //清除发送完成标志  }  void TF0_isr() interrupt 1     //每104us进入一次中断  {  static u8 i; //记录进入中断的次数      TH0=65440/256;      TL0=65440%256;      i++;  if(i>=1 && i<=8)      {          if((sbuf&(1<-1)))==        {              TX=0;          }  else        {              TX=1;          }      }  if(i==9)  //停止位     {          TX=1;      }  if(i==10)         {          TR0=0;          i=0;          ti=1; //发送完成      }  }  void main(){      TX=1; //使TX处于空闲状态      Timer0_Init();      Isr_Init();  while(1)      {          Send_Byte(65); //0x41          delay(60000);      }  }

    实验引入了定时器0来控制发送线上的各个位的保持时间。首先main函数进入,TX置1则使发送线处于空闲,这时候发送方和接受方都处于空闲。接下来初始化定时器0,TR0置0表示还不要启动定时器0。接着中断系统初始化,此时中断系统已经开启。进入while循环,先进Send_Byte()函数,将65传给形参dat,dat再将65赋值给sbuf,到这里准备工作就做好了。接着TX置0,这个是起始位,要保持这个起始位104us。于是就启动定时器TR0置1,计时器开始计数。当第一次溢出的时候,也就是过了104us,进入中断,同时接收方也侦测到了这个突然被拉低的信号,于是迅速启动自己的定时器。进入中断子函数后,先是重装定时器初值,然后i加1,也就是当i=1时,就应该发送数据的最低位了,总共有8位数据,所以使用条件语句if(i>=1 && i<=8)来判断是否发送完数据位。然后再通过if(i==9) 来发送停止位,最后当i=10时,也就是发送完了,这时候要关闭定时器(那么程序也就),同时i置0,ti置1(才能跳出while(ti==0)循环),最后将ti置0,保证下次要发送字节时让程序停留在while(ti==0)。

    片上串口试验

    以上说的是虚拟串口,上文中谈到与串口相关的引脚P3.0与P3.1,事实上51单片机自带片上串口,那这个串口又该怎么使用呢?

    片上串口支持同步模式与异步模式。简单来说同步模式就是指有时钟线,而异步模式无时钟线。这里的时钟线是指在同步通信时,用一根线专门传输时钟信号,这个信号用来与要发送的每一位保持同步,这样就避免了例如异步通信中因为采用定时器而引入的时间误差。

    片上串口还支持8位模式和9位模式。如下图所示

    290578ab786969efb2c0592e419880a6.png

    其中D0-D7是一个字节的8个位。9位模式只是多了一个位TB8,这个TB8的作用是奇偶校验或多机通信。奇偶校验原理这不加分析。多机通信时比如主机只发送数据给网络中的一台地址为0x02的设备,这时候先让TB8为1,前面的D0-D7则为地址即0x02,之后再让TB8为0,前面的D0-D7则为数据了。

    上面设置了片上串口的模式,另外还要设置串口的波特率。

    片上串口的波特率等于定时器1工作在方式2时溢出率的32分频。如果要定时器1工作在方式2,那么TMOD=0x20。另外要保证为32分频,我们还必须设置计数器初值。设晶振为11.0592Mhz,则定时器的计数脉冲为F=f/12,则定时器每计一个脉冲的时间为T=12/f。又令计数器的起点为x,则溢出一次要计的脉冲数为(256-x)。所以在计数起点为x时,溢出一次的时间为t=12/f*(256-x)。则对应的溢出率为1/t=f/(12*(256-x))。对应的波特率就为b=f/(384*(256-x))。

    x=256-f/(384*b)

    其中f为晶振频率,b为希望的波特率,x为定时器的计数起点TH1的值。

    例如当晶振为11.0592M,希望波特率为9600bit/s,则TH1=253。题外话,我们同样可以演算出在其他常用波特率情况下,TH1始终为一个整数。这里也就解释了为什么51里面选用了11.0592M的晶振而不是12M,这样就保证了串口的时序更加准确,虽然牺牲了定时器的准确度。

    片外串口发送一个字节

    实验二,片外串口发送一个字节。

    好了现在开始我们的实验之旅。直接看代码吧。

    [cpp] view plain copy# include "reg51.h"#define u16 unsigned int# define u8 unsigned charvoid delay(u16 x){while (x--);}void Uart_Init() //串口初始化 {    SCON = 0x50; //8位异步模式     TMOD |= 0x20; //定时器1工作方式2     TH1 = 253; //9600bit/s     TR1 = 1;}void Send_Byte(u8 dat){    SBUF = dat; //启动发送,只需要把发送内容给SBUF这个寄存器 while (TI == 0); //等待发送完成,因为TI为1时表示在发送停止位     TI = 0;}void main(){    Uart_Init();while (1)    {        Send_Byte('m');        delay(60000);    }}

    实验二较之实验一,代码减少了很多,而且不用考虑繁琐的位发送时序。只需要明白各个寄存器SCON,TMOD,TCON,SBUF的用法。TI是SCON中的第一位,为发送中断请求标志位。在本方式中,在停止位开始发送时由内部硬件置位,响应中断后TI必须又软件清零。

    片上串口发送一个字符串

    实验三、片上串口发送一个字符串

    上面介绍了如何发送一个字节,那如何发送一个字符串甚至文本呢?这里我们首先介绍下字符串的概念。

    字符串:从存储器的某个地址开始,连续存放多个字符的ASCII码,并且在最后一个字符的后面存放一个0,这段连续的内存空间就叫字符串,最后的0叫字符串的结束符。注意这里的0和加单引号的0不是一个概念,加单引号的0是指0的ASCII码。

    数组与字符串的关系:字符串是数组的一种特殊情况,数组在特定条件下可当做字符串用。C语言用双引号描述一个字符串,如“abcd”。

    下面我们通过一个实验来展示如何发送字符串。我们实验的目标是打印字符串“Hello World ! 第一!”到打印机。直接上代码。

    [cpp] view plain copy#include "reg51.h"#define u16 unsigned int  #define u8 unsigned char  void delay(u16 x){  while(x--);  }  void Uart_Init() //串口初始化  {      SCON=0x50; //8位异步模式      TMOD|=0x20; //定时器1工作方式2      TH1=253;//9600bit/s      TR1=1;  }  void Send_Byte(u8 dat)    //串口发送一个字节  {      SBUF=dat; //启动发送,只需要把发送内容给SBUF这个寄存器  while(TI==0); //等待发送完成,因为TI为1时表示在发送停止位      TI=0;  }void Send_String(u8 *str)   //发送一个字符串  *str为字符串第一个字符的地址  {      abc:      //标号  if(*str != 0)      {          Send_Byte(*str);          str++;  goto abc;         }   }    void main(){      Uart_Init();  while(1)      {         Send_String("Hello World! 第一!");         Send_Byte(10);         delay(60000);         delay(60000);      }  }

    实验结果展示

    实验效果

    891829f6e3e5ad53222038b3d0ab4182.png

    免责声明:本文内容来源于网络,文章版权归原作者所有,意在传播相关技术知识&行业趋势,供大家学习交流,若涉及作品版权问题,请联系删除或授权事宜。

    d9b15996e43e02a7488096aa7b957efc.png

    End

    68c8e3292593910b47738a7d1223494a.png

    华清2004年企业内训起家,有自己的研发中心,更好的让理论和实践相结合。给很多世界500强企业做过内训以及技术合作,师资雄厚;公开出版的系列教材也都为畅销书籍,更有很多高校用作教学用书。如果您想更深入了解华清,扫描联系华妹吧,还可免费报名试听哟!

    b7800a57ffd84ec07a6ef9d3c570416f.png

    点下在看,你就是最靓的仔儿!

    展开全文
  • C语言用双引号描述一个字符串,如“abcd”。 下面我们通过一个实验来展示如何发送字符串。我们实验的目标是打印字符串“Hello World ! 第一!”到打印机。直接上代码。 [cpp] view plain copy#include "reg51.h"#...
  • 先看表 3-1,表中列出了 KEIL uVision2 单片机c语言编译器所支持的数据类型。一、变量和运算符Cx51中的算术运算符二、函数函数可分为主函数、标准库函数、自定义函数三类。1、主函数Cx51语言程序中有且只能有一个...
  • 上一节,我们利用C语言编程单片机仿制了达文西的“古怪手电筒”,达成了“在有光的时候就会亮,在没有光的情况下绝对不会亮!”的目标。其实在此基础上,C语言还能做些更好玩的东西。例如,制作一个小灯,这个小灯的...
  • 学习C语言,先从读程序开始!这一点是过来人的经验之谈。本文建议大家选择一款图形编程软件,本文选择了Mixly。一、首先,介绍一下arduino UNO控制器内部电压的问题。v 高电平(5V):对应数值是1,输入状态3.5V-5.5V...
  • 总结一下我个人的编程风格及这样做的原因吧,其实是为了给实验室写一个统一的C语言编程规范才写的。首先声明,我下面提到的编程规范,是以前自己给自己定的,不是c语言里面规定的。 一件事情,做成和做好中间可能隔...
  • 设计“古怪手电筒”这里计划仍然使用C语言编程 51 单片机完成这种设计,那么,51 单片机就是“古怪手电筒”的大脑,它决定“古怪手电筒”是否发光。而为了实现“有光才亮,无光不亮”的机制,5...
  • 上一节介绍了如何使用C语言编程单片机控制步进电机转动,在文章最后提到,只要再结合感光器件,我们就能够制作一个“人工向日葵”,如下图:可以看出,单片机控制步进电机带着“箭头”始终指向光源,就好像向日葵...
  • 上一节介绍了如何使用C语言编程单片机控制步进电机转动,在文章最后提到,只要再结合感光器件,我们就能够制作一个“人工向日葵”,如下图:可以看出,单片机控制步进电机带着“箭头”始终指向光源,就好像向日葵...
  • 流星雨电路图元器件清单 以下是程序设计#include//头文件void delay_ms(unsigned int a)//延时函数{unsigned int i,j;for(i=a;i>0;i--)for(j=110;j>0;j--);}void main()//主函...
  • 设计“古怪手电筒”这里计划仍然使用C语言编程 51 单片机完成这种设计,那么,51 单片机就是“古怪手电筒”的大脑,它决定“古怪手电筒”是否发光。而为了实现“有光才亮,无光不亮”的机制,5...
  • 上一节使用 C语言控制单片机 IO 交替输出高低电平,实现了 LED 小灯的闪烁效果,核心代码如下: while(1){ P20 = 0; delay(10); P20 = 1; delay(10); } IO 输出的高低电平持续时间都是 10 个单位,一个完整的周期内...
  • c语言delay的用法。

    千次阅读 2020-10-24 14:49:45
    下面小编就跟你们详细介绍下c语言delay的用法,希望对你们有用。  c语言delay的用法如下:  假设一个延时函数如下:  void delay()  {  uint i;  for(i=0;i<20000;i++);  }  我们怎么来算呢...
  • c语言delay的用法

    2020-12-15 18:04:38
    转自:http://www.pinlue.com/article/2020/03/3100/4110073899413.html
  • 转自:http://www.pinlue.com/article/2020/03/3100/4110073899413.html
  • 转自:http://www.pinlue.com/article/2020/03/3100/4110073899413.html
  • 学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好。Keil软件是目前最流行...学习之前请先安装KEILC51软件,在学会使用汇编语言后,学习C语言编程是一件比较容易的事,我们将通过一系列的实例介绍C...
  • c语言及单片机delay延时函数延时函数1、是什么2、为什么3、用在哪里?4、怎么做1、循环延时 延时函数 延时函数,作为一种常用函数,在不同的领域有不同的用处。而在嵌入式以及C语言的编写中,我们常常遇到需要自己来...
  • delay 文件夹内包含了 delay.c 和 delay.h 两个文件,这两个文件用来实现系统的延时功能,其中包含 7 个函数:void delay_osschedlock(void); void delay_osschedunlock(void); void delay_ostimedly(u32 ticks); ...
  • 则需判断P3.0是否变成低电平0,if(k1==0)//提前定义sbit k1=P3^0 3、 延迟十毫秒进行消抖delay(10)//这里的10是由delay函数决定的 4、再次判断k1是否仍然为0,若k1仍然为0,则说明不是干扰信号,而是按键被按下 ...
  • extern “C”可以告诉编译器这是一个用C语言写的库,请用C的方式链接它。重要提示:如果c库被以C++的方式链接会报找不到函数的错误。 然后,我们的这个库里面的函数又依赖于Synwit原厂库,所以要引用SWM320.h这个...
  • 前言:在“混音大舞台”中,Delay是一个戏份很足的角色。在EDM类型的歌曲中,Delay几乎随处可见,所以,了解Delay效果器势在必行。一、Delay的前世今生先来给出定义,延时就是让信号延迟一段时间后再进行重放。要想...
  • delay_short()和 delay()这两个函数是延时函数,delay_short()函数是靠空循环来实现延时的,delay()是对 delay_short()的简单封装, 在 I.MX6U 工作在 396MHz(Boot ROM 设置的 396MHz) 的主频的时候delay_short(0x7...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 410
精华内容 164
关键字:

c语言delay

c语言 订阅