2009_0316 – 使用定时/计时器

这一次的程序写得实在太久了,整整两个星期!其实硬件原理很简单,只是C语言不过关,进度被拖慢了。

首先说说定时器/计数器。其实这就是单片机里专门的一块特殊功能寄存器,说白了,就是一个八位或更高位的能够自动加1的“RAM”,而从0加到2的8次方(八位的慢值)中间所经过的时间,就是计时时间了,这就有点像日本电玩机里那个用手一摇就会在四个滚筒上分别出现0到9这十个数的玩具一样~这就是我对计时器最直观的认识,当然原理绝对不会那么简单,不过我们能知道怎么用就够了。

关于TMOD TCON以及低八位和高八位的设置过几天用到更复杂的形式时再说。

今天用最简单的计时器0的工作方式0,让P1口第一个LED在计数时间之后改变亮灭的状态。亮灭之间的时间用计时器来处理,也就是从初始到溢出的时间,这之后跳转到中断程序,让P1的0口状态翻转

//compose a very easy program using timer_0 as a delay
/*
How to initialize a timer
step1. TMOD
setp2. TH0,TL0
step3. EA = 1,ET0 =1
step4. TCON, TR0 = 1
step5. when TF0 overflows,go to interupt
*/

#include<reg52.h>
sbit P1_0 = P1^0;       //reg52.h文件中只对P1口八个端口全部做了定义,现在单独用第一个口就要单独再声明一次

main()
{
    TMOD = 0x01;
    TH0 = 0x01; TL0 = 0x01;
    EA = 1; ET0 = 1;
    TR0 = 1;

    while(1);
}

void change(void) interrupt 1
{
    P1_0 = !P1_0;
    TH0 = 0x01; TL0 = 0x01;
}

这个程序最精彩的地方就是while(1); 这里运用一个永远无法再跳到下一步去的循环来使程序不断跳到中断程序中。
烧入程序后的效果如下:

  http://www.tudou.com/v/IIaXgA3ZYb8

数字集成电路命名规律

2009_0316

拿到一个数字集成电路,可以看到表面标有识别的信息,一般写法如上面图所示。

A – 一般有74和54两种,其中74为民用级别,54为军用级别。民用和军用两个级别最大的区别在整个模块的工作温度范围不同,军用比民用更耐低温更耐高温,所以工作范围比民用要大很多。

B – 是子系列的名称,根据特性的不同标以不同的标号,具体如下
L:低功耗
H:高速
S:肖特基
LS:低功耗消特基
ALS:先进低功耗肖特基
AS:先进肖特基
LS:低功耗消特基
HC:高速CMOS电平
HTC:TTL工作电平,可与74LS系列互换使用

C – 具体的型号

一般在图所示命名最前方还有两个英文字母,表示的是生产厂家

2009_0228 – 流动数码管显示程序

接着上次的实验,这次只需要改变工作的数码管以及其显示的数字即可。我的实验板上有8个数码管,我安排为轮到第几个数码管工作,那个数码管就显示出它的位数,比如第0个数码管工作就显示0,第7个数码管工作就显示7。
其实,这次只需要在上次程序的基础上做小小的修改即可。毕竟上次是在同一个数码管上显示8个数字,这次只是不断的改动显示数字即工作的数码管,所以只需要运用一个相应变化的数组即可实现工作数码管的变换。以下是整个程序的流程图:

未命名

将第一个框单独设为一个while循环,实现数组的初始化,而剩余两个框设为一个for循环,来实现工作数码管及其相应显示代码的移动。程序如下所示

/*****************************************************
Project : LED display
Version : V1
Date    : 2009_0228
Author  : Lemy Wong           
Company : N/A                    
Comments: change displaying numbers and the LED that works

Chip type           : AT89S52
Program type        : Application
Clock frequency     : 12 MHz
*****************************************************/
#include <reg52.h>
main()
{
    int m = 0;
    int n = 0;                  // a proper initialization for short –>  int m = 0 ,n = 0;
    int LED_change[] = {0,1,2,3,4,5,6,7};
    int number_change[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};  // initialize an array could not use a constant in[]
    void delay();

    while(1)
    {
        m = 0;
        n = 0;
        for(m == 0 , n == 0 ;m <= 7 ;m++ ,n++)
        {
            P0 = number_change[n];
            P2 = LED_change[m];
            delay();
            delay();
            delay();
        }

    }
}

void delay()
{
    int i = 30000;
    while(i–);
}

程序烧写之后再实验板上运行的效果如下面的视频所示

http://www.tudou.com/v/92G6e-7-iJM

##########c语言复习###########
这次编写这个程序出现了几个问题,首先,数组的初始化还是不熟悉,第二,变量的初始化其实可以有更简练的写法。查过相关课本后,对这两个问题进行一下总结:
1.数组的初始化
这次编写程序时,由于在更换工作数码管和显示代码的时候要使数组元素移动,所以设置了一个带变量的数组元素,所以最初的程序在初始化数组的时候写成了LED_change[m]之类的,结果马上被编译器检测出问题。
其实数组的维度是绝对不能出现变量的,这是因为程序运行之前检测到数组的时候,计算机立即检测其维度,来分配相应的内存空间。正因为这样,如果我们把数组的维度设置成一个变量,则计算机根本无法知道到底要分配多少内存空间给数组,这就使得整个程序编译的时候出问题。所以,初始化数组的时候,绝对不能用一个变量来放到其维度中。
正如上次程序一样,将数组维度制空是一个很不错的初始化方法,管它维度是多少,我用了多少就让计算机自己去计算出到底是多大的维度就得了。所以LED_change[]才是一个更简单更保险的初始化的方法
2.变量初始化的简化
连续初始化若干个变量如果像下面这样只有两个变量的话,下面的初始化方法还不算太麻烦
    int m = 0;
    int n = 0; 
可是如果有十几个变量要同时初始化的时候,这样写明显就显得很累赘了。所以,这里可以用逗号运算符将若干个变量初始化在同一行隔开,这样看起来还是写起来都会更舒服。
不过有个问题,切忌不能写成 int a = b = c = d = 0;的形式~

2009_0226 – 计算并检验数码管显示代码

我所使用的实验板中数码管是共阴的,电路图如下所示

2009_0226

数码管中八个LED分别对应于a b c d e f g dp,按照左高位右地位排列就是dp g f e d c b a。
由于是共阴的数码管,阴极连到了一起,所以想要点亮相应的LED就必须得使相应的位置1,比如要出现数字1,就要使b和c位为1而其他位为0,也就是十六位的数06,如此就可推算出由0到7的相应a到dp的组合(就是显示码),分别为0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f共六个。当然也可以继续推算出8 9 10 b c E的相应代码。
现在要做的就是写一个c51程序,把所推算的显示码送到数码管中,看看显示码和相应的数字是否符合。
代码如下

/*****************************************************
Project : LED display
Version : V1
Date    : 2009_0226
Author  : Lemy Wong           
Company : N/A                    
Comments: using array to change what the LED display displays

Chip type           : AT89S52
Program type        : Application
Clock frequency     : 12 MHz
*****************************************************/
#include <reg52.h>
void delay()       //function of delaying
{
    int n = 30000;
    while(–n);
}

main()
{
    int display_code[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};  //initialize an array
    int i;

    P2 = 0x00;                //get the first LED display work
    for(i = 0 ;i <= 7; i++)
    {
        P0 = display_code[i];
        delay();
    }

烧如程序后,实验板的情况如下视频所示,果然显示了从0到7的一个循环。实验成功!

http://www.tudou.com/v/fGupflYeU98

###########C语言复习###########
1.数组的初始化时可以定义其维度,也就是方括号[]内的数,但是由于这样得计算出数组元素的个数,当元素过多时计算不方便,所以一个更好的方法就是不填入维度,而让计算机自己计算。
2.数组元素要放到花括号{}之中

2009_0221 流水灯程序(c)语言

//以移位的方式让LED呈现流水形式
#include <reg52.h>
void delay()   //延时程序
{
    int n = 30000;
    while(–n);
}

void main()
{
    P1 = 0xfe;     //初始化P1口,实现P1.0亮其它灭
    while(1)
    {
        if(P1 == 0xfe)   //进入初始化状态
        {
            while(1)   
            {
                P1 <<= 1;   //左移内存中的数实现P1.1亮,在循环中逐渐点亮其他引脚的LED
                P1 |= 0x01;
                delay();
                if(P1 == 0x7f)break;  //左移最多能到到0x7f,此后要右移,才能实现“流水”的形式
            }
        }

        if(P1 == 0x7f) 
        {
            while(1)
            {
                P1 >>= 1;      //右移了
                P1 |= 0x80;
                delay();
                if(P1 == 0xfe)break;
            }
        }
    }
}

1.让流水灯呈现一亮一灭的效果(其一)

(虽然我写的并不是什么好文章,但是转载前请你告诉我一声,谢谢 联系方法 odawnw at gmail.com)

文章可能不是很专业,如果有哪个和我一样是学习单片机的初学者的话,咱们可以私下交流一下,你可以跟着留言,也可以给我发email,欢迎大家一起互相讨论互相学习互相进步。
篇前话 –>
汇编语言(Assembly Language,简称AL,其中assembly是装配的意思)作为早期的硬件交流语言,AL帮助了早期进入80×86系列单片机的学者进行较为广泛的硬件程序开发。不过随着时代的推移,C语言以及其他一些与硬件相配的程序语言的涌现使得汇编语言不再是开发硬件的最佳选择。不过,对于初学者来说,学习汇编语言能够帮助我们清楚的认识硬件的结构以及程序和硬件之间的关系,所以想要开发单片机的朋友倒不妨先出略了解一些基于80×86的汇编语言知识,再去研究别的单片机以及其开发语言。虽然80×86系列单片机现在普遍不再实用,可是它确实众多高校里电子与自动化专业的入门课,如果不认真对待,那么至少你就会挂科。
我的计划是,先了解80×86单片机以及概略地学习汇编,再进入AVR单片机并用回以前学过的c语言作为开发程序,接着,如果有时间的话就接触ARM,毕竟这个在消费电子产品上的应用相当广泛。

正文 –>
学习汇编语言必须首先有个认识,你得和硬件打交道,而这也是硬件程序设计和软件程序设计最大的区别。所以,AL的学习并不能只限制与语言的学习上,而应该非常重视其控制的硬件部件。

流水等呈现一亮一灭的效果是一个入门的AL程序,要学会这个程序那么得首先了解单片机的结构和工作原理,发光二极管的工作原理,接着就是到程序本身,而这里面我们得知道一些最基础的程序,以及AL的设计思路。

1.1单片机的结构和工作原理
b408b2a12aec098046106475 
上图为一单片机引脚的结构图,其实说白了,单片机就是一个可以把输入信号转换成那么多个引脚里不同的输出信号,以此来达到“控制”的效果。所以看一个单片机的引脚图最重要的就是看它从哪里输入,又从哪里输出。不过AL设计里不过多考虑输入的问题,而知需要考虑输出在哪个引脚(这个后面会有提到)。一般单片机都喜欢用途中P2开头的引脚(就是右下角从P2.7到P2.0的八个引脚),这个信息我们必须得知道。
另外,我们必须知道单片机是一步一步的进行工作的。这是什么意思,就比如军训的时候教官口里喊的“一二一”口令。在单片机里,“一二一”口令是由晶振来发出的,也就是说晶振就是单片机里的“教官”,不过懂得这个也没多大用处,更重要的是我们得知道单片机是一步一步的去进行工作的,每一个口令下它处理一个事件,下一个口令再处理下一个事件,懂得这个我们也就知道汇编语言的没一句话也就是在每一个口令下,让单片机进行的某一种事件的操作(这个后面会有提到)。

1.2发光二极管的工作原理
二极管的工作原理是当给它加以正向的电压时它会导通,也就是会发光,而要是加以反向的电压的话它就不能导通(这一现象的物理分析设计模拟电路的知识这里暂且不讨论)。我们就是要使用单片机的这些引脚(更具体的说就是使用P2里的八个引脚)来控制加在二极管两端电压的方向的,不过对于单片机来说,我们不采用“电压”的说法,而用“电平”这个词,其实实质是一样的,只是叫法不同而已。与电压相对,正向电压在单片机里一般定义为“高电平”,相反也一样。

1.3单片机和发光二极管间的接法
图片1
既然我们要用单片机来控制发光二极管,那么就需要将这个控制的单片机和被控制的发光二极管接起来。由于P2引脚有八个,所以相应的就要接入八个发光二极管(如图),而这八个发光二极管组成一排灯,一般叫做“流水灯”,之所以叫“流水”是因为我们可以通过程序的设计来让这八个等实现一种类似流水的效果(这个下面会有讲)。
虽然这个图很复杂,可是我们需要看的只有右边部分,也就是P2引脚到发光二极管这一小段。其中+5V的电压提供一个工作电压,电阻是用来保护二极管不少坏的。汇编语言可以很轻松的对P0到P7这八个引脚进行专门的控制(下面有讲到),我们假设从P2.0口输入了一个相对发光二极管的正向电压(发光二极管额“正向”规定为三角形到竖直线的方向,也就是向左的方向),这在单片机来说也就是低电平(为什么?看看有一个+5V的电压已经使发光二极管处于正向偏置的状态了,我们只需要把P2.0口设置为电压为零,使得“+5V -> 电阻 -> 发光二极管 -> 单片机内部 -> 地”形成一个回路,这样就可以使发光二极管导通而发光了)。

2.1AL的基本语句 – 送数据以及循环
我们来看一个基本的程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lp:  mov  p2, #00H
      ajmp  lp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
这就是一个简单的送数据以及循环的与语句。其中lp是loop的意思,mov是move,ajmp是a jump的意思,表示跳转(这个很重要,是循环)
前面已经提到了,单片机是一步一步地进行工作的,而我们设计的汇编语言的每一行都是每一步里命令单片机要进行怎么样的操作。现在先让我们把上面的汇编语言翻译成我们一般说的话,至少我们得读懂它是什么意思,对吧,接着我们再去了解没一句话这样设置的含义,只有这样我们才可以写出属于自己的语句。
首先设置一个名为lp的循环:进入第一步,我们由某个地方(某个地方是什么?这个是以后的知识,不过现在既然提到了就说一下,是从内存中取数)取出一个00H这个数(H的意思就是十六进制,所以00H转换成二进制也就是0),输入到P2的所有引脚。接着进入第二步,我们再跳转回这个循环。
现在我们已经“翻译”了这个语句了,不过似乎还不是很了解其效果。那么,就把这个程序“烧”到单片机里面去看看有什么效果吧。“烧”进去后发现,八个灯全部亮起。
现在我们来理解一下这个程序。首先我们得知道,既然单片机是一步一步的进行工作的,那么我们就会利用到循环来在相连的几步里进行同一个操作。正如这里的程序,首先第一步我们将P2口的八个引脚送入了0这个数,也就是说把八个引脚全部设置为低电平,在这一步中我们就使得发光二极管点亮了,而下一步我们再次返回到第一步中,再次使得发光二极管点亮,如此不断的进行循环,出来的效果也就是发光二极管一直亮了。
不过这里有些细节得注意,每一步之间是否会有些间隔?答案是的确有,不过这个时间间隔相当小,大概是几微秒,这个时间间隔完全无法被人眼所感觉到,所以我们就看不到法官二极管是闪烁的,而是一直在亮。
现在我们来看看mov语句,它的语法如下
mov 端口,#数字
如果是数字则要加#,如果是地址则不需要加了。
另外,AL讲究一种形式美,所以我们这里mov和ajmp这两个隶属于lp虚幻的操作都是对称地缩进的。

2.2神奇的#
再回到我们的标题,我们是要设计一亮一灭,可是上面我们只设计了亮,我们怎么让它灭掉呢?这里就不得不提一下神奇的#了
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lp:  mov  p2, #11111111B
      ajmp  lp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
如果我们的单片机以及发光二极管的接法限制了高电平使发光二极管灭的话,上面的语句就是让八个管子全灭掉的AL。也许你注意到了,这和上面最初的AL有点不一样,的确,上面我使用的十六进制,而这里我使用了二进制。为什么要这样,我们得考虑到P2口是有八个引脚的,如果我们要一个一个地对每个引脚进行控制那么我们需要有八个量,不过好在有了神奇的#,我们就可以用八个二进制来对其进行控制,更神奇的是,四位二进制对应一位十六进制,所以这八个二进制我们又可以用两位十六进制来表示。不过使用八位二进制来表达的话可以很直接的对每个引脚进行控制(设置是高电平还是低电平),要注意到,如果你使用了八进制那么你的数后面就需要以B结尾。
现在我们用二进制来重写最初让它灭的程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lp:  mov  p2, #00000000B
      ajmp  lp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
超级简单,其实就是把1改成0!
我们再看一下下面的程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lp:  mov  p2, #00000001B
      ajmp  lp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
把它烧进去,再执行后出现什么效果?对!最右边的那个发光二极管灭了!这就是#号的神奇之处!它能够对每个引脚进行控制!
现在,知道了怎么点亮发光二极管,也知道了#号的神奇之处,我们来变换出一些花样吧,其实质需要把八位二进制进行小小的改动就可以了。也许你会很天真的想到,要是我再用其它七个每个六排的有单片机控制主的发光二极管组合成一个8×8的发光二极管矩阵的话,似乎就可以写出A,B,C以及很多很多字,甚至可以画画了?对的,这个想法的确很好,不过实现出来可能有点麻烦,毕竟你得同时设置八个单片机的程序。实际上我们做起来并不适用八个单片机,而知需要一个就可以了,不过这个程序要理解起来还需要很多很多基础知识,不过总有一天我们一定会掌握的。

 

回顾这次的学习,我们从最基本的知识入手,接着从最基本的让灯亮切入,接着我们了解到神奇的#,用它来变换出了几个花样,再接着我们又发挥了想象力,设想字和画是否会用8×8的发光二极管来设计得到……其实学习过程就是这样,从简单入手再慢慢复杂,从慢速切入再慢慢提速。要知道单片机是一个日益更新的领域,新的知识新的挑战我们每天都会遇到,所以我们必须得不断的学习,无论难的知识还是简单的知识,不过,当我们一步一步的进行学习,到最后再回顾我们的成就时,就会感到一种由衷的幸福。所以,虽然技术更新带来的挑战很大,可能会让人背负很大的压力,可是我们把它转换成一种学习带来的成就感的话,就会感觉到有无穷无尽的驱动力了。

The C Programming Language | Exercise 1-8

/*Exercise 1-8*/
#include <stdio.h>

main()
{
    int c,nb,nt,nn;
    c = 0;
    nb = 0;
    nt = 0;
    nn = 0;
    printf ("please enter a paragraph to test its blanks,tabs and newlines");
    while ((c = getchar()) != EOF)
        if (c == ‘ ‘)
                ++nb;
        if (c == ‘\t’)
                ++nt;
        if (c == ‘\n’)
                ++nn;
    printf ("OK,after computing,the pc will tell you there are"
            "%d blank(s) %d tab(s) and %d new line(s)",nb,nt,nn
            );
    system("pause");
}

———————-
我发现我很喜欢重新翻出这一条作业来做!不过,多做以后可以发现很多问题.

1.有关函数的声明
这里采用的方法绝对是最原始最浪费内存的,不过在第二章以后将采用新的方法
2.printf函数中显示的部分双引号内部的信息只能写一行,要是有多行则每行都应该使用一个引号括起来
3.最后一句话system(pause);用于防治程序运行后马上关闭,不过现在还不是很清楚为什么要这样做

The C Programming Language 1-9

练习1-9 编写一个将输入复制到输出的程序,并将其中连续的多个空格用一个空格代替。

这个问题其实考虑起来有个思维过程。先看一个例子
I have a blank I  have  two  I   have   three
这里理所当然要使用到getchar()函数来处理,所以要有字符流的思维,因此上面的字符串可以归为三种情况:(每次getchar()返回一个字符)
1,返回的是字母,则直接另输出的就是字符本身即可
2,返回的是空格,且该空格的前一个字符是字母,则另该空格为其本身即可
3,返回的是空格,但该空格的前一个字符也是空格(也就是体重所谓的“多个空格”),则将其替换为”
上面的三种情况可以由三个if语句来构成,但是这样写过于麻烦。不妨回头看一下三个情况,似乎可以合并成两个。的确,情况一和情况二所作的处理都是相同的,即另输出为输入,因此这里可以用一个if-else语句来简化。考虑到情况3较容易陈述,故将其放入if中,其余情况用else代替,可缩短整片语句。

#include <stdio.h>

main()
{
int n = 0;
int str[n] = getchar();

while (n = 0;str[n] != EOF;n++)
    if(str[n] == ‘ ‘ || str[n – 1] == ‘ ‘)
        str[n] = ”;
    else
        str[n] = str[n];
    putchar(str[n]);
}

——————————————-
但是这条程序还是有问题,编译器检测到数组的初始化有问题(
int str[n] = getchar();这部分有问题),可是我查阅了数组初始化的资料发现似乎没错啊~真不知道为什么了。先放着,以后想到再回头看看。
同时这条程序还有一个隐藏的危险,就是利用数组来存储getchar()返回的内容可能会放不下,而出现错误。这个我记得似乎有解决方法的~不过暂时想不出来了,想到了再回头重新弄弄尴尬


以下是姬失准的参考程序

The C Programming Language 1-9

其中方法一和我的思路相同,但似乎他用了stdlib.h中的lastc,这个啥玩意我不知道Confused 以后研究stdlib.h了再回头看看,似乎他那条很简洁的。
方法二的话实在是看不懂了。Sarcastic

关于“取模”运算的实验

一直以来都无法理解取模的具体操作。现在不妨先做个实验,究竟取模的结果是什么。代码如下:

#include <stdio.h>
main()
{
    printf("1 \37 3 = %d\n",1%3);
    printf("2 \37 3 = %d\n",2%3);
    printf("3 \37 3 = %d\n",3%3);
    printf("4 \37 3 = %d\n",4%3);
    printf("5 \37 3 = %d\n",5%3);
    printf("6 \37 3 = %d\n",6%3);
}

执行生成文件后形成如下内容:
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0
先分析大于三的数与三进行取模运算。4%3上1余1,其余的5和6也是类似的计算,所以大于三的数与三进行取模运算比较好理解。接着再来看小于及等于三的数,先看三本身,取模上一余0,所以为0;接着看2,上0余下的就是2本身,同样1也是余下1本身。
所以可以总结出取模运算实质就是“除法后余下的零头”但是要注意“上0进行除法”的情况,即上述1和2与3进行取模运算。

——–
题外话,这个程序编译的时候出现了点小问题,在printf函数的双引号内想要打出百分号不能够直接键入%,因为这里的1%3在双引号中表示的是1这个数用三个字符的位置来显示。所以必须得换作用转义字符,查ASIIC表后发现百分号是第37个,所一用/37来表示百分号,前后记得要加上空格。

The C Programming Language Exercise1-8

Exercise1-8
Write a programto count blanks,tabs and newlines

1.1st try
———————————————————-
#include <stdio.h>
/*initialize the varibles*/
int c,b,t,n;

/*get start the counting*/
printf("Please enter a sentence for testing")
if ((c = getchar()) = ‘ ‘)
++b;
else if ((c = getchar()) = ‘t’)
++t;
else if ((c = getchar()) = ‘n’)
++n;

printf("blank(s) —> %d
tabs(s) —> %d
newline(s) —> %d",b,t,n);
———————————————————-
This time I’ve made a mistake.I don’t use the ‘while’ loop,instead I use if wondering it may run a loop in program,but the complier says there’s many errors in this program,I think it’s something to do with the ‘if’
So,now I should remember that:‘If’ can’t run a loop!
While,let’s go back to the loop itself,in order to get in into loop,we should use ‘while’,noting
while((c = getchar()) != EOF)
the key word ‘EOF’ make it possible to go over all the sentenc character as what the book teaches.
Hey!Poor guy!You forgot main() at the beginning of this program!!!!!!
What’s more,the printf("") shouldn’t be noted like this!

2. 2nd try
———————————————————-
#include <stdio.h>
/*initialize the varibles*/
main()
{
int c,b,t,n;

b = 0;
t = 0;
n = 0;

printf ("Please enter a sentence for testing");

/*start the counting*/
while ((c = getchar()) != EOF)
if (c = ‘ ‘)
++b;
else if (c = ‘t’)
++t;
else if (c = ‘n’)
++n;

/*output the result*/
printf("blank(s) %dntabs(s) %dnnewline(s) %d", b,t,n);
}
———————————————————-
This time I’ve get this program run,but,It really don’t run as what I expected,I hope to have this result that,after entering a sentence for test and then click on ‘ctrl + c’ and then an ‘Enter’,I expect it dispaly such words like:
blank(s) 3
tabs(s) 4
newline(s) 5
ect.
But the result is against it!It doesn’t display anything,and it really makes me very anoying