D플립플롭을 4개 연결한 시프트 레지스터이고 이전의 디지털 금고와는 달리 같은 클락펄스가 들어간다. 프리셋 기능은 EXTI (외부 인터럽트)를 사용했다.
회로는 이전 글의 디지털 금고할때 쓰던 회로를 그대로 사용했는데 실제 사용하는건 왼쪽부터 LED 4개와 맨 아래의 버튼 1개 뿐이다.
15부터 시작해 무작위로 보이는 순서로 변화함
위의 상태도와 일치하게 순환한다.
PG3과 연결된 버튼은 풀다운저항이고 Rising Edge 인터럽트로 설정한 버튼이 눌려 인터럽트 발생시, 각 플립플롭의 출력 Q값이 다 1111로 초기화된다.
소스코드
main.h 내 구조체 정의
typedef struct {
uint8_t Q;
uint8_t clockbefore;
}JKFF;
main.c
전역변수 선언 및 초기화
/* USER CODE BEGIN PV */
JKFF jkff[4]={
{1,0},
{1,0},
{1,0},
{1,0}
};
/* USER CODE END PV */
인터럽트로 변수 값을 변화시켜야되서 전역변수로 선언했다.
사용자 정의 함수의 원형
/* USER CODE BEGIN PFP */
void JKflipflopF(uint8_t J, uint8_t K, uint8_t Pulse, JKFF *JKFFx);
/* USER CODE END PFP */
EXTI 인터럽트 콜백함수. USER CODE BEGIN 0 구간에 작성했다.
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
for(int i=0; i<4; i++){
jkff[i].Q = 1;
jkff[i].clockbefore = 0;
}
}
이전 글과는 달리 PG3만 MX에서 인터럽트 포트로 설정했기 때문에 콜백함수 내에 GPIO_PIN 번호를 구분하는 구문은 써주지 않았다.
2022.05.22 - [MCU/STM32 (ARM Cortex-M)] - STM32 , 외부 인터럽트 ( EXTI ) 사용하기
콜백함수가 호출되면 각 플립플롭의 출력을 1로 만들고 구조체 내에 클락펄스를 기억하는 멤버는 0으로 초기화한다.
while문 내에 토글시켜서 클락펄스를 줄 clock 변수와 임시 데이터 저장을 위한 temp 배열 생성
/* USER CODE BEGIN 2 */
uint8_t clock = 0;
uint8_t temp[4] = {0,};
/* USER CODE END 2 */
while문 내
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
clock ^= 1;
temp[0] = jkff[0].Q;
temp[1] = jkff[1].Q;
temp[2] = jkff[2].Q;
temp[3] = jkff[2].Q ^ jkff[3].Q;
JKflipflopF(temp[0], !temp[0], clock, &jkff[1]);
JKflipflopF(temp[1], !temp[1], clock, &jkff[2]);
JKflipflopF(temp[2], !temp[2], clock, &jkff[3]);
JKflipflopF(temp[3], !temp[3], clock, &jkff[0]);
for(int i=0; i<4 ; i++){
if(jkff[i].Q)
GPIOD->ODR |= (0x1 << i);
else
GPIOD->ODR &= ~(0x1 << i);
}
HAL_Delay(500);
/* USER CODE END WHILE */
}
0.5초 간격으로 클락펄스를 준다.
D 플립플롭의 입력은 1, 0 또는 0, 1 밖에 없으며 K쪽에 !연산자를 써서 인수로 전달한다.
그리고 JKflipflopF 함수가 순차적으로 호출되며 값이 계속 변하는데 호출의 순서와 상관없이 루프의 이전 상태의 값에 따라 출력이 나와야 하므로 호출 전 temp에 값을 미리 저장해두었다.
맨 위의 회로도를 참고하면
Db=Qa
Dc=Qb
Dd=Qc
이고
Da=Qc^Qd 이다.
마지막 for문은 각 플립플롭의 출력이 1이면 불을 켜는 부분이다.
플립플롭함수 정의
/* USER CODE BEGIN 4 */
void JKflipflopF(uint8_t J, uint8_t K, uint8_t Pulse, JKFF *JKFFx){
if(Pulse == 0 && JKFFx->clockbefore == 1){
if(J==1 && K==1){
JKFFx->Q ^= 1;
}else if(J==0 && K==1){
JKFFx->Q = 0;
}else if(J==1 && K==0){
JKFFx->Q = 1;
}
}
JKFFx->clockbefore = Pulse;
}
이전글에서 만들었던 걸 사용했다.
'임베디드 개발 > STM32 (ARM Cortex-M)' 카테고리의 다른 글
STM32 , PWM 주기 변경으로 수동 부저 ( Passive Buzzer ) 제어 , 실시간으로 ARR 변경시 동작 멈추는 현상 해결 , 멜로디 출력 (2) | 2022.05.27 |
---|---|
STM32 , UART 통신 ( 수신 ) 을 이용한 PWM 서보모터 ( SG90 ) 제어 + 펄스폭 찾아내는 팁 (3) | 2022.05.26 |
STM32 , Timer Interrupt 타이머 인터럽트 사용하기 (TIM2) (5) | 2022.05.25 |
STM32 , 디지털 금고 프로그래밍으로 구현 ( 시프트 레지스터 응용 ) (0) | 2022.05.24 |
STM32 , 동기식 / 비동기식 상향/ 하향 카운터 프로그래밍으로 구현하기 ( JK 플립플롭 , IC 7490 / 7492 ) (0) | 2022.05.23 |