임베디드 커뮤니티 [W.O.E]
cafe.naver.com/okh0217
8.HSO
알람시계를 써본적이 있을 것이다. 임의의 시간을 예약해놓고 그 시간이 되면 알람이 울리게 하는 알람 시계...
MCS-96 계열의 마이크로컨트롤러도 일종의 알람기능이 있는데 바로 HSO 이다.
자..그렇다면 알람을 울리는 일 대신 CPU에게 예약시켜줄 수 있는 일은 어떤 것이 있는지 알아보자.
참고로 High Speed Output의 약자로서 포트를 순간적으로 많이 써도 하드웨어가 직접적으로 처리하기 때문에 CPU에 부하를 덜주게되는 뭐 그런거란다.
◈예약할수 있는 사건
-고속 출력 포트 1개 이상을 0 or 1로 만들 수 있다. -->hso 인터럽트 발생
-A/D 컨버젼 스타트
-타이머 2 리셋
-4개의 소프트웨어 타이머 인터럽트를 생성
(소프트웨어 타이머가 같은 시간 간격내에 발생되도록 했다면 IOS1의 여러개의 상태비트가 1로 된다.)
◈원리
고속 출력을 내보낼 시간과 사건을 CAM에 예약해둔다.
(HSO_COMMAND 와 HSO_TIME 레지스터를 이용하는데 8개까지 예약 가능)
타이머 값과 CAM 내용을 비교해서 프로그램된 시간값이 같으면 정해진 사건이 알아서 발생한다.
시간은 timer1 혹은 timer2 둘중의 하나를 기준시간으로 이용한다.
(타이머 2를 쓸때에는 고속모드는 쓰면 안되며 보통 모드를 써야한다.)
☞CAM 이란?
책에선 CAM 파일 어쩌구 하는데 그냥 ‘24비트 레지스터‘라고 생각하면 된다.
이것의 구조까지는 상세히 알 필요없다고 생각하는 바 ...그냥
사건 발생할 "시간"이 저장될 16비트 + "어떤 사건"이 발생하는지 저장할 8비트가 고로 총 24비트라고만 생각하자.
8개까지 예약할수 이유는 CAM에 8개밖에 없기 때문이다.
어쨋든 CAM에 저장되어 있는 시간값과 현재의 타이머값을 비교해서 같으면 사건이 발생한다는....이 정도만 알면 된다고 본다.
그러고보면 나는 그냥 설정만 해주면 CPU가 다 알아서 해주니 CPU를 설계한 사람들은 참 대단한거 같다. ^^
◈HSO인터럽트
HSO_COMMAND 레지스터를 이용하여 HSO.0~5핀에 대해서 각각 인터럽트를 설정할수 있다. 또 IOS2를 이용하여 HSO의 이벤트를 체크할수 있다.
IOS0 : HSO핀들의 현재 상태를 나타냄
IOS1 : HSI나 HSO에서 어떤 사건이 인터럽트를 발생시켰는지
IOS2 : 어떤 HSO 사건이 출력되었는지 알 수 있음
◆ RC 서보 모터 구동하기
우선 RC서보 모터가 어떤 것인지 그놈을 구동하기위해 어떤 방법을 이용하면 되는지 참고 사이트를 갈켜주겠다. ^^
RC서보 모터가 어떻게 생긴넘인지 모르는 분을 위하여 -- 외국 사이트
서보 모터 구동방법 - 충북대 제어계측학과 방극찬 선배의 개인 홈페쥐 -- 로봇자료실에 있다.
또다른 외국 사이트 - 그림과 함께 잘 나와있음
정리하자면 서보 제어신호를 만드는 방법은 펄스를 만들되 일정한 주기(5ms~20ms) 안에서 듀티비만 조절하면 된다.
펄스를 만드는 방법은 소프트웨어 타이머, HSO, 타이머 ,PWM등이 있는데 80c196에서 PWM은 최대 주기가 51.2us밖에 안되기 때문에 서보모터를 돌리기에는 부적절하다.
◆예제 소스
/*=============================================================================== 2002.2.6 ☞시리얼 인터럽트를 이용한 서보 모터 테스트용 프로그램ver.1 키보드로 숫자 1,2,3중 하나를 누르면 90도 간격으로 회전. '1': -90도 '2': +90도 '3': 0도(중앙) ☞ 주기: 15ms (5ms는 모터가 떨림) ☞ output pin : HSO.1 HSO사건이 발생할때마다 인터럽트가 걸리게한다. HSO.0~HSO.5중 어떤것을 해도 상관없으나 HSO.4,HSO.5를 선택할때는 IOC1 레지스터 설정해야함. ===============================================================================*/ #pragma model(kc) #include<80c196.h> #define T_15MS 18750 /* 18750state * 0.8us = 15ms*/ #define SERVO_CENTER 1875 /* 1875state * 0.8us = 1.5ms*/ #define SERVO_LEFT 875 /* 875state * 0.8us = 0.7ms*/ #define SERVO_RIGHT 2875 /* 2875state * 0.8us = 2.3ms*/ unsigned char command; unsigned int highpulse_state ; unsigned int lowpulse_state ; unsigned char temp,buffer; void sel_state(char ch) { switch(ch) { case '1': highpulse_state = SERVO_LEFT; break; case '2': highpulse_state = SERVO_RIGHT; break; case '3': highpulse_state = SERVO_CENTER; break; } lowpulse_state = T_15MS - highpulse_state; } char get(void) { char ch; do{ temp |= sp_stat; }while( (temp & 0x40) == 0 ); temp &= 0xbf; buffer = sbuf; return buffer; } void put(void) { do{ temp |= sp_stat; }while( (temp & 0x20) == 0 ); sbuf = buffer; temp &= 0xdf; } void INT06_ser_int(void) { char ch; asm pusha; temp |= sp_stat; if(temp & 0x40) { ch = get(); put(); } sel_state(ch); asm popa; return; }
void INT03_hso_int(void) { command ^=0x20; /* hso_command.5 반전 --> HSO 출력을 toggle시킨다. 0←→1*/ hso_command = command; if( (command & 0x20) == 0) hso_time = timer1 + highpulse_state; else hso_time = timer1 + lowpulse_state; return; } void serint_init() { baud_rate = 0x40; baud_rate = 0x80; /* baud rate : 19200*/ sp_con = 0x09; ioc1 = 0x20; /* TXD출력핀으로 설정 */ } void hso_set() { ioc2 = 0x80; /* clear CAM and disable locking*/ wsr = 15; timer1 = 0; } /*------------------------------------------------------------------------------------------- ☞소스 설명 맨처음 HSO.1은 high이다. ->hso_time = timer1로 설정했으므로 시작하자마자 인터럽트가 걸린다. ->command = low가 됨. 조건에 의해 hso_time = timer1 + highpulse_state 즉 인터럽트가 걸린시점(맨처음)에서 highpulse_state 만큼 시간이 경과한후 low가 되라는 뜻이다. -> 시간이 경과해서 low가 되는 동시에 또 인터럽트가 걸린다. ->반전 command = high 조건에 의해 hso_time = timer1 + low 즉 인터럽트가 걸린시점에서 low 만큼 더해진 시점에서 펄스는 high가 된다. -------------------------------------------------------------------------------------------*/ void main(void) { serint_init(); hso_set(); highpulse_state = SERVO_CENTER; lowpulse_state = T_15MS - highpulse_state;
wsr = 0; /* hso_command write로 하려면 HWIN 0 설정 */ int_mask = 0x48; /* HSO , serial interrupt*/
enable(); command = 0x31; /* HSO.1 set */ hso_command = command; hso_time = timer1 ; /* 시작함과 동시에 high로 함.*/
while(1); } |