关于单片机中断模块的心得体会

单片机中断的理解。

1.首先52单片机里6个中断源(比51多一个T2),具体如下图1.1所示。


图1.1  52单片机6个中断源

      在这里我们需要注意的是,定时系统是单片机硬件的组成部分,52单片机引脚如图1.2所示。   由图1.2可以看出功能复用的引脚,比如T2/P1.0、T0/P3.4等。

为什么我们在单片机定时中断程序中看不到响应中断函数的子函数呢?这正是它的巧妙之处! 定时系统与CPU和晶振通过某种关系连接,于是当CPU一旦设置定时功能,定时器便在晶振作用下自动开始计时。通过加1计数器计时,当计数器计满后,便开始产生中断。   


图1.2  52单片机引脚图

2.在使用中断时,必须使用的两个寄存器:IE和IP。其中IE(interrupt enable,中断允许寄存器)、IP(interrupt priority,中断优先级寄存器)。IE的字节地址为A8H,IP的字节地址是B8H,对于我们在单片机C语言编程,用不到,字节地址用于汇编语言中。图2.1和图2.2分别是IE和IP寄存器的各位定义。


图2.1  IP各位


图2.2  IE各位

具体各位怎么设置,查看书就好。

3.定时器的两个寄存器。TMOD和TCON。即为Time mode和time control


图3.1  TCON各位


图3.2 TMOD各位


图3.3  定时器/计数器的四种工作方式

     在这里有一个问题就是设置TH0和TL0的初值。

4.在这里我主要分析下串口通信实现上位机和下位机之间是如何通讯的(采用方式1来实现编程)。

         通讯分并行和串行两种方式,单片机系统信息的交换多采用串行通信方式。

单片机的串行口设定为4种.波特率定义为每秒传输的二进制代码的位数,它表示的是单片机或计算机在串口通讯时的速率,即:1波特=1位/秒(单位bps)。

下面来分析在波特率为9600bps,系统晶振频率为11.0592MHZ,方式1下来TH1和TL1中装入的数值。

设所求的数位X,则定时器每计256-X个数溢出一次。 每计一个数的时间为一个机器周期,一个机器周期为12个时钟周期,于是可知计一个数的时间为12/11.0592MHZ(s), 定时器溢出一次的时间为[256-X]*12/11.0592MHZ(s)。T1的溢出率就是它的倒数。因此代入方式1波特率的公式可求得波特率为

(2SMOD/32)*(T1溢出率),代入9600可得,X=253,转化为十六进制为0xFD。

          另一细小问题。若这里采用12MHZ的晶振,则计算出T1的初值不是一个整数,这样通信将会产生累计误差。

在单片机串行口的描述中有个SBUF寄存器。SBUF----串行数据缓冲寄存器。SBUF是两个独立的串行数据缓冲器(一个是receive,一个是transmit),两个SBUF公用同一块地址99H。接收数据时,写a=SBUF;发送数据时,写SBUF=a。为什么是这样呢?让我们看图4.1


  图4.1  SBUF数据的接收与发送

     接下来让我们了解下串行口控制寄存器SCON(serial control)。图4.2是串行口控制寄存器,图4.3是串行口工作方式。


图4.2  串行口控制寄存器


图4.3  串行口工作方式

在这里我们选用的是方式1,即SM0=0,SM1=1。图4.2中,在方式1中,我们需要注意REN(允许串行接收位)、TI(发送中断标志位)、RI(接收中断标志位),其中TI和RI是硬件置1,软件清零。方式1是10位数据的异步通讯,1位起始位,8位数据位,1位停止位。由图1.2我们可以看出TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。波特率由定时器的溢出率决定(T1定时器每溢出一次的时间的倒数,即为溢出率)

下面程序是有串口输入数据,控制LED灯。

#include<reg52.h>

 #define uchar unsigned char

 #define uint unsigned int

 unsigned char flag,a,i;

 

 void init()// 寄存器初始化

 {

     TMOD=0X20;//T1定时器工作方式2(8为初值自动重装)

      TH1=0Xfd;//波特率为9600bps下,装初值

      TL1=0Xfd;

      TR1=1 ;  //启动定时器1

      REN=1 ; //允许串口接收

      SM0=0;  //串口工作方式1(10位异步收发)

      SM1=1;

      EA=1; //全局中断

      ES=1; //串口中断

 }

 

  void main()

 {

     init();

      while (1)//在这框架下进行

      {

             if(flag==1)//当标志位flag为1时,说明程序已经执行过串口中断

             {

                    ES=0;//必须将ES清零,否则陷入死循环

                    flag=0;   //清零

                    SBUF=a;//向串口发送数据

                    while(!TI);     //判断是否发送完,发送完,会由硬件将TI置1

                    TI=0; //手动清零取消中断申请

                    ES=1;  //打开串口中断

             }

      }

}

 

 void ser()   interrupt4    //串口中断服务程序

 {

     RI=0;/*  进入这里,则说明已产生中断(收到或发送数据);开始没有发

送任何数据,那程序必定是收到数据,此时RI由硬件置1,所以必须将RI清零*/

      P1=SBUF;//接收数据

      a=SBUF;//重新将SBUF赋给a

      flag=1;   //flag置1

}

   PS:我是新手,学习单片机有2个月时间。 自己画原理图、PCB,送出去做板子、焊板子调试。 感觉对单片机编程调试时,一定要把各个相关寄存器搞清楚,因为编程无非就是在操作相关寄存器。

在ClassWizard中响应ID为~Dlg中的WM_TIMER消息。 使用SetTimer(nIDEvent,time,NULL)来建立一个定时器,关闭定时器用KillTimer(nIDEvent)函数。 然后可以响应ON_WM_TIMER消息来响应一个定时器完成一次记时后的程序。 响应方式如下: void CTimeDlg::OnTimer(UINT nIDEvent) { if(nIDEvent==1000)//间隔为5秒 { //处理事件 } elseif(nIDEvent==1001)//间隔为10秒 { //处理事件 } CDialog::OnTimer(nIDEvent); } 以下是给出一个串口通信定时检查接收数据的部分代码 void CMyDlg::OnOpenCom() { // TODO: Add your control notification handler code here if( f_open_com==true ) { f_open_com = false; GetDlgItem(IDC_OPEN_COM)->SetWindowText("打开通信端口"); CloseHandle(hComm); KillTimer(1000); /// 关闭定时器 return ; } SetTimer(1000, 1000, NULL); ///nIDEvent==1000,time=5000ms const char *ComNo; DCB dcb; string temp("COM1"); ComNo = temp.c_str(); hComm = CreateFile( ComNo , GENERIC_READ|GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0); if( hComm==INVALID_HANDLE_VALUE ) /// 如果端口未打开 { MessageBox("打开通信端口出错!" , "Comm Error" , MB_OK); return ; } /// 将dcb地址传入,以取得通信参数 GetCommState(hComm,&dcb); /// 得知目前通信状态 dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; /// 字节为8 dcb.Parity = NOPARITY; /// Parity为None dcb.StopBits = ONESTOPBIT; /// 1个停止位 if( !SetCommState( hComm , &dcb)){ MessageBox("通信端口设置出错!" , "Set Error" , MB_OK ); CloseHandle(hComm); return; } GetDlgItem(IDC_OPEN_COM)->SetWindowText("关闭通信端口"); f_open_com = true; } void CMyDlg::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default char inbuff[1024]; DWORD nBytesRead , dwError; COMSTAT cs; /// 取得状态 ClearCommError( hComm , &dwError , &cs); /// 数据是否大于所准备的缓冲区 if( cs.cbInQue > sizeof(inbuff) ) { PurgeComm(hComm , PURGE_RXCLEAR ); /// 清除通信端口数据 return ; } ReadFile(hComm , inbuff , cs.cbInQue , &nBytesRead , NULL ); //接收通信端口的数据 inbuff[cs.cbInQue] = '\0'; MessageBox("打开通信端口出错!" , "Comm Error" , MB_OK); m_Receive.Format("%s",inbuff); UpdateData(false); CDialog::OnTimer(nIDEvent); } 李杨: for(int i=0; ;i++ ) { ... Sleep(5); if(i>...) {AfxMessageBox("错误XXX"); return;} }//跳出后记得停止一些机器动作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值