2024年重庆大学通信工程大二课程:《MCU原理及应用——基于恩智浦S12X的嵌入式系统开发》实验课程记录。(错误在所难免,请多斧正!🙏)
见下前言
一、实验目的
掌握C语言综合编程方法,掌握并行I/O接口、TIM(Timer)定时器、中断等功能部件的使用规则和应用方法,熟悉中断处理程序的安排。
【并行I/O接口】
并行:数据传输方式之一。在并行接口中,数据作为一个数据组(通常是8位、16位或更多位组成的字节或字)同时通过多条线路进行传输。
【TIM:定时器】
TIM实际上是一个可编程计数器,也是高速I/O通道。
其核心为一个16位自由运行计数器(TCNT,Timer Counter),原始时钟来自MCU总线时钟,通过预分频生成不同频率的时钟,再对该时钟进行递增计数。可作为定时时间基准、产生波形输出、测量输入波形、统计脉冲或边沿个数和产生脉宽调制输出。
对于本实验使用的MCU,为增强型捕捉定时器(ECT,Enhanced Capture Timer)。需要在寄存器名称前加 “ECT_”。
【中断 Interrupt】
重要事件发生或异常产生并提出处理请求(中断源)时,CPU暂时停止执行当前程序,转向中断服务程序,中断处理完后返回原来程序地址继续运行。
二、实验内容
2.1 实现1s精确定时
每定时时间到,使开发板上接B口8位LED灯变化以对应表达(输出一个递增数),观察是否进入中断。调试时,可在中断服务程序中设置断点,以方便观察是否进入中断。
MCU为8MHz总线频率,利用MCU的ECT定时器通道0、中断功能部件。(教材P165)
【输出比较 OC】Output Compare。通过预置的数值与TCNT的值相比,确定动作。用于精确定时,定时时间的计算公式:
定时时间 = TCx预置常数 × 总线周期 × 预分频因子
总线周期 = 1 / 8 MHz = 125 ns
预分频因子 (教材P159)
PR[2:0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|---|
预分频因子 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 |
TCx预置常数 :16位二进制数,最大为 = 65535。实际所需写入的TCx值,应为 TCNT当前值+ 预置常数(因为定时器OC中的16位定时器计数器TCNT是自由运行的)
代码实现
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
static word outValue=0;
void main(void) {
/* put your own code here */
DisableInterrupts;
DDRB=0xFF;
PORTB=0xFF;
ECT_TSCR2=0x07;
ECT_TIOS=0x01;
ECT_TCTL2=0x00;
ECT_TFLG1=0x01;
ECT_TIE=0x01;
ECT_TC0=(word)(ECT_TCNT+62500);
ECT_TSCR1=0x80;
EnableInterrupts;
for(;;) {
_FEED_COP(); /* feeds the dog */
} /* loop forever */
/* please make sure that you never leave main */
}
#pragma CODE_SEG NON_BANKED
interrupt 8 void Timer0_ISR(){
ECT_TFLG1=0x01;
ECT_TC0=(word)(ECT_TCNT+62500);
outValue++;
if(outValue>255)outValue=0;
PORTB=~outValue;
}
硬件显示
实验四 2.1 实现1s精确定时
2.2 单位周期内统计脉冲次数
统计每 5s 时间内IOC6脉冲事件次数,结果送 B口 LED灯进行二进制表达。
- ECT通道7输出比较以定时 1s,时间到时 IOC7 引脚电平自动翻转(驱动开发板上 LED9);
- ECT通道6输入捕捉以检测脉冲(须设置内部上拉电阻),按键 SW6 每按动一次形成一个下降沿脉冲,由IOC6响应。通道6每1个中断中计数值递增;
- 通道0每5个中断后(即成5s定时)送结果。
- 每1s时间到LED9亮出x/熄灭,每5s时间到 LED1~7灯显示统计到的按键次数。
引脚复用:IOC0~7与T口的PT0~7引脚复用。复用使能时,DDRx寄存器作用无效。
代码实现
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
void delay_ms(unsigned int ms){
int i,j;
for(i=0;i<ms;i++){
for(j=0;j<1333;j++);
}
}
byte nPulseNums = 0; //脉冲数
byte time = 0; //时间计数
void main(void) {
/* put your own code here */
DisableInterrupts;
DDRB = 0xFF; //设B口(LED1~8)为输出
PORTB = 0x00; //LED全亮
nPulseNums = 0; //计数脉冲数为0
//TCNT设置
ECT_TSCR2 = 0x07; //溢出中断禁止;计数器自由运行;预分频因子:128
ECT_TIOS = 0x81; //通道7、0为输出比较,通道6为输入比较
ECT_TIE = 0xC1; //通道7、6、0中断使能
//通道7定时1s,IOC7引脚电平自动翻转
ECT_TCTL1 = 0x40; //通道7比较成功,电平翻转
ECT_TFLG1 = 0x80; //写1清除TIM通道7中断标志
ECT_TC7 = (word) (ECT_TCNT+62500); //通道7定时1s
//通道6输入捕捉脉冲
PERT = 0xFF; //T口内部拉电阻使能
PPST = 0x00; //T口上拉
ECT_TCTL3 = 0x20; //IC6下降沿捕捉
ECT_TFLG1 = 0x40; //写1清除IC6中断标志
//通道0送结果
ECT_TCTL3 = 0x02; //捕捉下降沿
ECT_TFLG1 = 0x01; //写1清除IC0中断标志
ECT_TSCR1 = 0x80; //TIM使能;中断标志普通清除
EnableInterrupts;
for(;;) {
//_FEED_COP(); /* feeds the dog */
} /* loop forever */
/* please make sure that you never leave main */
}
//通道6中断服务函数
# pragma CODE_SEG NON_BANKED
interrupt 14 void Timer6_ISR(){
DisableInterrupts;
ECT_TFLG1 = 0x40; //写1清除IC6中断标志
nPulseNums++; //脉冲数加1
EnableInterrupts;
}
//通道7中断服务函数
# pragma CODE_SEG NON_BANKED
interrupt 15 void Timer7_ISR(){
ECT_TFLG1 = 0x80; //写1清除通道7中断标志
ECT_TC7 = (word)(ECT_TCNT+62500); //重置预置数TC7
PTT = 0xFE; //给IC0送0触发中断
}
//通道0中断服务函数
# pragma CODE_SEG NON_BANKED
interrupt 8 void Timer0_ISR(){
time++; //1s定时成功
if(time == 5){
PORTB = ~nPulseNums;
delay_ms(200);
time = 0;
nPulseNums = 0;
}
}
失败了,LED1~8没有显示。
硬件显示
实验四 2.2 单位周期内统计脉冲计数
2.3 控制周期信号的生成
利用ECT定时器(TCNT)通道7定时(=8MHz)的专有中断标志自动清除,及自动复位计数器特性,同时检查:
PT0 | |
---|---|
1 | IOC7引脚自动输出翻转(输出周期为100ms的方波信号,LED9会闪烁) |
0(按键按下) | 信号保持为0电平 |
代码实现
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
static word preScale = 25000;
void main(void) {
/* put your own code here */
DisableInterrupts;
//DDRT &= 0xFE; //有无该句效果一样?
ECT_TSCR2 = 0x0C; //预分频因子:16;TCNT溢出中断禁止;OC7比较成功复位计算器
ECT_TIOS = 0x80; //定时器通道7 设为输出比较
ECT_TCTL1 = 0x40; //比较成功后,输出电平翻转
ECT_TFLG1 = 0x80; //中断标志清零
ECT_TIE = 0x80; //中断使能,输出比较成功时申请中断
ECT_TC7 = preScale; //输出比较寄存器预置数
ECT_TSCR1 = 0x90; //定时器模块使能,中断标志快速自动清除使能
EnableInterrupts;
for(;;) {
if ((PTT & 0x01) == 0x01){
ECT_TCTL1 = 0x40;
} else ECT_TCTL1 = 0x80;
//_FEED_COP(); /* feeds the dog */
} /* loop forever */
/* please make sure that you never leave main */
}
#pragma CODE_SEG NON_BANKED
interrupt 15 void Timer7_ISR(){
ECT_TC7 = preScale;
}
硬件显示
实验四 2.3 控制周期信号生成
总结
知识点很琐碎。尤其第二个...做得很累