实验五 PIT定时器、I/O综合

2024年重庆大学通信工程大二课程:《MCU原理及应用——基于恩智浦S12X的嵌入式系统开发》实验课程记录。(错误在所难免,请多斧正!🙏)

见下前言和注意事项
实验二 并行I/O接口、IRQ中断-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_73918454/article/details/139250471?spm=1001.2014.3001.5501


一、实验目的

掌握C语言综合编程方法,深化并行I/O口、PIT定时器(Period Interrupt Timer)、中断等功能部件的使用规则和应用方法,全面掌握中断处理程序的安排。

二、实验内容

2.1 实现1s精确定时

利用MCU的PIT定时器通道0、中断功能部件,实现1s精确定时( 8MHz总线频率)。

每定时时间到,使开发板上PE2高电平驱动的继电器控制LED10亮灭一下,观察是否进入中断。调试时,可在中断服务程序中设置断点,以方便观察是否进入中断。

定时时间公式】(比Timer定时时间多一倍,PIT最大定时2.09715 s,8MHZ下)

TimeOutPeriod = \frac{(PITMTLD+1)\times (PITLD+1)}{f_{BUS}} 

TimeOutPeriod:定时时间 1s

PITMTLD:微(Micro)定时器装载寄存器 = 159   (设置8位递减计数器载入的值,最大255)

PITLD:定时器装载(Load)寄存器 = 49999        (设置16位递减计数器载入的值,最大65535)

f_{BUS}:总线频率 = 8\times10^{6}

PIT使用与设置】PIT定时器初始化完成前,先不要使能(Enable)它,避免刚开始一段时间的定时不正确。完成装载寄存器的设置、8位微计数器的选择、定时器通道的打开等初始化工作后,再使能PIT。

代码实现

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */


void main(void) {
  /* put your own code here */
  DisableInterrupts;

  DDRE = 0xFF;      //PE2为输出
  PORTE = 0x0F;     //LED10灭
  
  PITCFLMT =0x00;   //关闭PIT定时器
  PITTF = 0x01;     //PIT通道0超时标志位写1清零
  PITMUX = 0x00;    //PIT通道0使用微计数器0
  PITMTLD0 = 159;   //设置微计数器0的装载寄存器
  PITLD0 = 49999;   //设置16位计数器0的装载计数器
  PITINTE = 0x01;   //使能PIT通道0中断
  PITCE = 0x01;     //使能通道0计数
  PITCFLMT = 0x80;  //使能PIT定时器

  EnableInterrupts;


  for(;;) {
    
    //_FEED_COP(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

#pragma CODE_SEG NON_BANKED  //中断服务函数定位声明
interrupt 66 void PIT0_ISR(){
  PITTF = 0x01;     //PIT通道0超时标志位写1清零
  PORTE = ~PORTE;   //1s到,PE2电平翻转,LED10亮灭交替
} 

硬件显示 

实验五_2_1_实现1s定时

2.2 LED数码管显示4×4行列式键号

设计软件译码、动态扫描的4位连排共阴级数码管显示函数(display),以及中断响应方式的进行4x4行列式键盘(PH0~7)扫描检测中断服务函数(PTH_ISR),主函数(main)中从而将键号按01~16在数码管的低2位上以动态扫描方式显示出来。(教材P149)

代码实现

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */

byte KeyVal,KeyNum,tmp;
byte SegCode[16] ={      //共阴极数码管段码0~F
0x3F,0x06,0x5B,0x4F,0x66,
0x6D,0x7D,0x07,0x7F,0x6F,
0x77,0x7C,0x39,0x5E,0x79,
0x71
};                   
byte LineCode[4] = {0xFE,0xFD,0xFB,0xF7};   //行扫描码

void delay_ms(unsigned int ms){
  int i,j;
  for(i=0;i<ms;i++){
    for(j=0;j<1333;j++);
  }
}

void display(){
  PORTK = 0x00;

  tmp = KeyNum&0x0F;
  PORTA = SegCode[tmp];
  PORTK = 0xF1;
  delay_ms(5);

  tmp = ((KeyNum&0xF0)>>4);
  PORTA = SegCode[tmp];
  PORTK = 0xF2;
  delay_ms(5);
}

void main(void) {
  /* put your own code here */
  DisableInterrupts;

  DDRA = 0xFF;    //PA口输出
  PORTA = 0x00;   //输出低电平
  DDRK = 0xFF;
  DDRH = 0x0F;
  PIFH = 0xFF;
  PIEH = 0xF0;
  PTH = 0xF0;

	EnableInterrupts;


  for(;;) {
    //_FEED_COP(); /* feeds the dog */
    display();
  } /* loop forever */
  /* please make sure that you never leave main */
}

#pragma CODE_SEG NON_BANKED

interrupt 25 void PTH_ISR(void){
  int i;   

  delay_ms(10);            //延时去抖动,等待键按下

  for(i=0;i<4;i++){        //逐行扫描
    PTH = LineCode[i];     //送行扫描码
    _asm("NOP"); 
    _asm("NOP");           //等待生效
    KeyVal = PTH;          //读取键值 

    if(KeyVal!=LineCode[i]){   //当前行有键按下时则按键找到,退出扫描
      break;                   //无键按下则二者相等
    }
  }
  if((KeyVal&0xF0)==0xF0){     //高4位列线值为F表示无键按下
    KeyNum = 0x00;
  }

  switch(KeyVal){
    case 0xEE:KeyNum = 0x01;break;
    case 0xDE:KeyNum = 0x02;break;
    case 0xBE:KeyNum = 0x03;break;
    case 0x7E:KeyNum = 0x04;break;
    case 0xED:KeyNum = 0x05;break;

    case 0xDD:KeyNum = 0x06;break;
    case 0xBD:KeyNum = 0x07;break;
    case 0x7D:KeyNum = 0x08;break;
    case 0xEB:KeyNum = 0x09;break;
    case 0xDB:KeyNum = 0x10;break;

    case 0xBB:KeyNum = 0x11;break;
    case 0x7B:KeyNum = 0x12;break;
    case 0xE7:KeyNum = 0x13;break;
    case 0xD7:KeyNum = 0x14;break;
    case 0xB7:KeyNum = 0x15;break;

    case 0x77:KeyNum = 0x16;break;
  }

  PIFH = 0xFF;
  PTH = 0xF0;
}

硬件显示 

实验五_2_2显示行列式键号

2.3 10s倒计时秒表设计

硬件定时器选PIT通道0中断,秒表数字变动使用动态扫描显示的低2位LED数码管,秒表启动使用按键SW5(即IRQ中断引脚)。

特别注意:10s到9s的时间也须间隔精确。

代码实现

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */


//变量设置
byte IRQ_IntFlag = 0;    //IRQ中断标志
byte num[11] ={          //数字0~10
0x00,0x01,0x02,0x03,0x04,
0x05,0x06,0x07,0x08,0x09,
0x10};
byte SegCode[10] ={      //0~9的共阴极数码管段码
0x3F,0x06,0x5B,0x4F,0x66,
0x6D,0x7D,0x07,0x7F,0x6F,
};
byte tmp;
byte cnt = 10;           //指10~0秒

//延时
void delay_ms(unsigned int ms){
  int i,j;
  for(i=0;i<ms;i++){
    for(j=0;j<1333;j++);
  }
}

//LED动态扫描显示
void display(){     
  PORTK = 0x00;
  //个位显示
  tmp = num[cnt]&0x0F;
  PORTA = SegCode[tmp];
  PORTK = 0xF1;
  delay_ms(5);
  //十位显示
  tmp = ((num[cnt]&0xF0)>>4);
  PORTA = SegCode[tmp];
  PORTK = 0xF2;
  delay_ms(5);
}


void main(void) {
  /* put your own code here */
  DisableInterrupts;
  //LED设置
  DDRA = 0xFF;
  PORTA = 0xFF;
  DDRK = 0x0F;
  
  //设置PIT定时器(定时1s)
  PITCFLMT =0x00;   //关闭PIT定时器
  PITTF = 0x01;     //PIT通道0超时标志位写1清零
  PITMUX = 0x00;    //PIT通道0使用微计数器0
  PITMTLD0 = 159;   //设置微计数器0的装载寄存器
  PITLD0 = 49999;   //设置16位计数器0的装载计数器
  PITINTE = 0x01;   //使能PIT通道0中断
  PITCE = 0x01;     //使能通道0计数
  PITCFLMT = 0x80;  //使能PIT定时器

  //SW5(IRQ中断设置)
  IRQCR = 0xC0;     //外部中断IRQ使能,下降沿触发

	EnableInterrupts;

  for(;;) {
    //计时前LED先显示10
    if(IRQ_IntFlag == 0){
      display();
    }
    //计时开始
    if(IRQ_IntFlag == 1){
      display();
      if(cnt == 0){
        IRQ_IntFlag = 0;   //10s倒计时结束
        cnt = 10;          //重新显示10,等待计数开启
      }
    //_FEED_COP(); /* feeds the dog */
    } /* loop forever */
  /* please make sure that you never leave main */
  }
}

#pragma CODE_SEG NON_BANKED  //PIT定时中断服务函数定位声明
interrupt 66 void PIT0_ISR(){
  //IRQ中断后才开始计时
  PITTF = 0x01;       //PIT通道0超时标志位写1清零
  if(IRQ_IntFlag == 1){
    PITTF = 0x01;     //PIT通道0超时标志位写1清零
    cnt--;
  }
} 

#pragma CODE_SEG NON_BANKED  //中断服务函数定位声明
interrupt 6 void IRQ_ISR(){
  IRQ_IntFlag = 1;         //置启动标志1
} 

硬件实现

实验五_2_3 10s倒计时


总结

要有耐心...很多代码之前有,复制过来修改下数据就能用了。

代码一定要有注释。时间久的话很容易忘记怎么写,重看代码又看不懂,要复制修改数据又不知道相应代码什么意思。

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qiming_Peng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值