请马潮老师再次帮忙解答mega48的T/C1执行CTC动作的问题
程序如下:; CPU: MEGA48
.equ fosc = 8 ; FOSC=8.0 MHz
.equ t1_all = 125000 ; T1定时的总时间(us)
.equ t1_940us= 940 ; time for pre_Vpp
.equ t1_20us = 20 ; time for emitting
.equ t1_120us= 120 ; time for after_Vpp
.equ t1_end = (t1_all-t1_940us-t1_20us-t1_120us)*fosc
.equ t1_940init= t1_940us*8+16
.equ t1_20init = t1_20us*8-4
.equ t1_120init= t1_120us*8-3
.equ t1_status = 0x0100 ; t1定时的状态
.equ t1_count= 0X0101 ; t1定时5ms的次数
.equ timer1_cnt=25 ; 定时1s的次数
.equ t1_125init= t1_all/timer1_cnt*8-2 ; 初始值
;.def timer1_count=R19
.INCLUDE "m48def.inc"
.ORG $000 ;精确定时产生秒号
STRT25: RJMP RST25
.ORG $00b ;T1 Capture
RJMP T1_OVFB ;4000133=62*65536-63099=62*$10000-$F67B/故TCC=$F67B
.ORG $01b
RST25:LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
RCALL T1_initial
LDI R16,0b00001001 ;不分頻
;STS TCCR1A, $00 ; COM1A1/COM1A0/COM1B1/COM1B0/-/-/WGM11/WGM10 (默认值:00H)
STS TCCR1B,R16 ; ICNC1/ICES1/-/WGM13/WGM12/CS12/CS11/CS10
;WGM13, WGM12, WGM11, WGM10 = 0100 -> CTC模式(MAX=OCR0A)
CS12,CS11,CS10 = 001 -> Fosc/1 (无分频,000->T/C停止) ;
SEI ;
HH1B: RJMP HH1B ;等待中断
;************** T/C1 初始化子程序 *******************
T1_initial:
LDI R16,$03
OUT DDRC, R16
LDI R16,$00
OUT PORTC,R16
LDI R16,timer1_cnt ;62次中断定出秒号
MOV R6,R16
LDI R16,$00 ;000->T/C停止
STS TCCR1B,R16 ;
LDI R16,$02 ;
STS TIMSK1,R16 ;允许T/C1的A匹配中断:
LDI R16,$00
STS TCNT1H,R16
STS TCNT1L,R16
LDI R16,HIGH(t1_940init)
STS OCR1AH,R16 ;写入OCR1A高8位
;对于扩展的I/O 空间段0x60 - 0xFF 只能使用ST/STS/STD 和LD/LDS/LDD 指令。
LDI R16,LOW(t1_940init) ;
STS OCR1AL,R16 ;写入OCR1A低8位
LDI R16, $10
STS t1_status, R16 ;T/C1的起始状态: 10
LDI R16,0b00000010 ;Vpp=1, Vemit=0
OUT PORTC,R16
RET
;*************** 中断服务程序区 ***************************
T1_OVFB:
LDS R16, t1_status
CPI R16, $10
BRNE STATUS_11
STATUS_10:
SBI PORTC,0
LDI R16,HIGH(t1_20init)
STS OCR1AH,R16 ;写入OCR1A高8位
LDI R16,LOW(t1_20init) ;
STS OCR1AL,R16 ;写入OCR1A低8位
LDI R16,$11
STS t1_status, R16 ;T/C1新的状态:11
RETI
STATUS_11:
CPI R16, $11
BRNE STATUS_01
CBI PORTC,0
LDI R16,HIGH(t1_120init)
STS OCR1AH,R16 ;写入OCR1A高8位
LDI R16,LOW(t1_120init) ;
STS OCR1AL,R16 ;写入OCR1A低8位
LDI R16,$01
STS t1_status, R16 ;T/C1新的状态:01
RETI
STATUS_01:
CPI R16, $01
BRNE STATUS_00
CBI PORTC,1
LDI R16,HIGH(t1_125init)
STS OCR1AH,R16 ;写入OCR1A高8位
LDI R16,LOW(t1_125init) ;
STS OCR1AL,R16 ;写入OCR1A低8位
LDI R16,$00
STS t1_status, R16 ;T/C1新的状态:01
RETI
STATUS_00:
LDS R16, t1_count
INC R16
STS t1_count,R16
CPI R16, timer1_cnt
BRNE STATUS_00_NOEND
LDI R16, $00 ; 25*5ms = 125ms
STS t1_count,R16
SBI PORTC, 0
LDI R16,HIGH(t1_940init)
STS OCR1AH,R16 ;写入OCR1A高8位
LDI R16,LOW(t1_940init) ;
STS OCR1AL,R16 ;写入OCR1A低8位
LDI R16,$10
STS t1_status, R16 ;T/C1新的状态:00
RETI
STATUS_00_NOEND:
LDI R16,HIGH(t1_125init)
STS OCR1AH,R16 ;写入OCR1A高8位
LDI R16,LOW(t1_125init) ;
STS OCR1AL,R16 ;写入OCR1A低8位
LDI R16,$00
STS t1_status, R16 ;T/C1新的状态:00
RETI (接上)
无论软件仿真(时序为:940us->19.88/20.13us->120/120.25us->124998.37/124998.12us)
还是烧写新片后均出现类似于 19.88/20.13us->120/120.25us->124998.37/124998.12us不稳定的时序,
在此敬请马老师给予解答,谢谢!
(补充:以上时间在以下断点处测量:
STATUS_10:
SBI PORTC,0
LDI R16,HIGH(t1_20init);断点检测
STATUS_11:
CPI R16, $11
BRNE STATUS_01
CBI PORTC,0
LDI R16,HIGH(t1_120init) ;断点检测
STATUS_01:
CPI R16, $01
BRNE STATUS_00
CBI PORTC,1
LDI R16,HIGH(t1_125init) ;断点检测
STATUS_00:
LDS R16, t1_count
INC R16
STS t1_count,R16
CPI R16, timer1_cnt
BRNE STATUS_00_NOEND
LDI R16, $00 ; 25*5ms = 125ms
STS t1_count,R16
SBI PORTC, 0
LDI R16,HIGH(t1_940init);断点检测
以上4个断点的时序检测出现变化情况,归结于定时不精确) 把项目要求和经费给我吧,很快就给你完成. 我是打工仔啊,别嘲笑我啦 我不是嘲笑你.
我是教师,因此希望你能真正掌握本领,把基础打好.换句话讲,是督促和希望你能掌握打鱼的本领,而不是送条鱼给你.
我已经将思路给你了,你应该通过自己的努力把它实现.如果老是要个程序,那么连打工仔也做不了. /*****************************************************
Chip type : ATmega48
Clock frequency : 4.000000 MHz
Memory model : Small
External SRAM size: 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#define OCR1A (*(unsigned int*)0x88) //补充定义16位寄存器OCR1A,它在mega48.h中未定义
char step;
// Timer 1 output compare A interrupt service routine
interrupt void timer1_compa_isr(void)
{
switch (step)
{
case 0:
OCR1A = 3758;
break;
case 1:
OCR1A = 79;
break;
case 2:
OCR1A = 4319;
break;
case 3:
OCR1A = 199;
break;
}
if (++step >= 4) step = 0;
}
void main(void)
{
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T
PORTB=0x00;
DDRB=0x02; // 在PORTB.2上输出波形
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 4000.000 kHz
// Mode: CTC top=OCR1A
// OC1A output: Toggle
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
// desired value: 940uSec
// actual value: 940.000uSec (0.0%)
TCCR1A=0x40;
TCCR1B=0x09;
OCR1AH=0x0E;
OCR1AL=0xAE;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x02;
// Global enable interrupts
#asm("sei")
while (1)
{
// Place your code here
};
}
==========================
试试看. 回复【5楼】machao
-----------------------------------------------------------------------
DDRB=0x02; // 在PORTB.2上输出波形
马老师,应该是PORTB.1吧! OCR1B在一些模式下不支持可调的PWM输出吧?
页:
[1]