승코딩당당당

[TC275] 4자리 FND 카운터 구현하기 (스위치 제어) 본문

개발/임베디드

[TC275] 4자리 FND 카운터 구현하기 (스위치 제어)

승코딩당당당 2026. 2. 23. 15:53

 

이번 실습에서는 TC725 보드에서 GPIO를 이용해 4자리 FND(7-Segment) 디스플레이를 제어하는 카운터 시스템을 구현한다. 하드웨어 SPI 모듈을 사용하는 대신, SCLK·RCLK·DIO 핀을 직접 제어하는 비트뱅잉(Bit-Banging) 방식의 소프트웨어 SPI로 데이터를 전송하도록 구성하였다.

 

카운터 값은 0부터 9999까지 증가하며, 각 자리 숫자는 _LED_0F[] 배열을 통해 7-Segment 패턴으로 변환된다. 4자리 FND는 멀티플렉싱 방식으로 동작하며, send_port() 함수를 통해 자리 선택 신호와 세그먼트 데이터를 순차적으로 출력하여 사람이 보기에 동시에 켜진 것처럼 보이도록 구현하였다.

 

또한 두 개의 스위치를 이용해 동작을 제어한다.

  • SW1 : 카운터 시작 / 정지 토글 (하강 에지 검출 방식)
  • SW2 : 카운터 값 리셋

스위치 입력은 이전 상태(prevSw1, prevSw2)와 현재 상태를 비교하는 방식으로 에지를 검출하여, 단순 폴링 구조에서도 정확한 토글 동작이 이루어지도록 설계하였다.

 

이번 실습을 통해 다음 내용을 함께 정리할 수 있다.

  • GPIO 기반 소프트웨어 SPI 구현 방식
  • 7-Segment(FND) 멀티플렉싱 동작 원리
  • 스위치 에지 검출(Edge Detection) 기법
  • Start/Stop/Reset 제어 로직 설계

 


 

코드 (Cpu0_Main.c)

/**********************************************************************************************************************
 * \file Cpu0_Main.c
 * \copyright Copyright (C) Infineon Technologies AG 2019
 * 
 * Use of this file is subject to the terms of use agreed between (i) you or the company in which ordinary course of 
 * business you are acting and (ii) Infineon Technologies AG or its licensees. If and as long as no such terms of use
 * are agreed, use of this file is subject to following:
 * 
 * Boost Software License - Version 1.0 - August 17th, 2003
 * 
 * Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and 
 * accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute,
 * and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the
 * Software is furnished to do so, all subject to the following:
 * 
 * The copyright notices in the Software and this entire statement, including the above license grant, this restriction
 * and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all 
 * derivative works of the Software, unless such copies or derivative works are solely in the form of 
 * machine-executable object code generated by a source language processor.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 
 * COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN 
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
 * IN THE SOFTWARE.
 *********************************************************************************************************************/
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#include "IfxStm.h"
#include "IfxCpu_Irq.h"
#include "IfxPort.h"
#include "IfxPort_PinMap.h"

// SPI port define
#define SCLK IfxPort_P00_0
#define RCLK IfxPort_P00_1
#define DIO  IfxPort_P00_2

// Switch 핀 정의
#define SW1  IfxPort_P02_0   // 시작 / 정지 토글
#define SW2  IfxPort_P02_1   // 리셋

uint8 _LED_0F[10] = {0xC0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};

void initGPIO(void);
void send(uint8 X);
void send_port(uint8 X, uint8 port);

IfxCpu_syncEvent cpuSyncEvent = 0;

void core0_main(void)
{
    IfxCpu_enableInterrupts();

    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());

    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&cpuSyncEvent);
    IfxCpu_waitEvent(&cpuSyncEvent, 1);

    initGPIO();

    int n = 0;
    uint8 run = 0;
    uint8 prevSw1 = 1;
    uint8 prevSw2 = 1;

    while(1)
    {
        // 스위치 입력 처리
        uint8 curSw1 = IfxPort_getPinState(SW1.port, SW1.pinIndex); // 1: not pressed, 0: pressed
        uint8 curSw2 = IfxPort_getPinState(SW2.port, SW2.pinIndex);

        // SW1: HIGH -> LOW 
        if ((prevSw1 == 1u) && (curSw1 == 0u))
        {
            run ^= 1u;   // 0->1, 1->0
        }

        // SW2: 하강 에지에서 카운터 리셋
        if ((prevSw2 == 1u) && (curSw2 == 0u))
        {
            n = 0;
        }

        prevSw1 = curSw1;
        prevSw2 = curSw2;

        // 현재 값 FND에 표시
        int n1 = n % 10;
        int n2 = (n % 100) / 10;
        int n3 = (n % 1000) / 100;
        int n4 = (n % 10000) / 1000;

        for (int i = 0; i < 50; i++)
        {
            send_port(_LED_0F[n1], 0x1);  
            send_port(_LED_0F[n2], 0x2);  
            send_port(_LED_0F[n3], 0x4);  
            send_port(_LED_0F[n4], 0x8);   
        }

        // 카운터 증가 (run==1일 때만)
        if (run != 0u)
        {
            n++;
            if (n > 9999)
                n = 0;
        }
    }
}

void initGPIO(void)
{
    // SPI 핀 출력 설정
    IfxPort_setPinModeOutput(
        SCLK.port,
        SCLK.pinIndex,
        IfxPort_OutputMode_pushPull,
        IfxPort_OutputIdx_general);

    IfxPort_setPinModeOutput(
        RCLK.port,
        RCLK.pinIndex,
        IfxPort_OutputMode_pushPull,
        IfxPort_OutputIdx_general);

    IfxPort_setPinModeOutput(
        DIO.port,
        DIO.pinIndex,
        IfxPort_OutputMode_pushPull,
        IfxPort_OutputIdx_general);

    // 초기 Low 설정
    IfxPort_setPinLow(SCLK.port, SCLK.pinIndex);
    IfxPort_setPinLow(RCLK.port, RCLK.pinIndex);
    IfxPort_setPinLow(DIO.port,  DIO.pinIndex);


    // 스위치 입력 설정
    IfxPort_setPinModeInput(
        SW1.port,
        SW1.pinIndex,
        IfxPort_InputMode_pullUp);

    IfxPort_setPinModeInput(
        SW2.port,
        SW2.pinIndex,
        IfxPort_InputMode_pullUp);
}

void send(uint8 X)
{
    for (int i = 8; i >= 1; i--)
    {
        if (X & 0x80)
            IfxPort_setPinHigh(DIO.port, DIO.pinIndex);
        else
            IfxPort_setPinLow(DIO.port, DIO.pinIndex);

        X <<= 1;

        IfxPort_setPinLow(SCLK.port, SCLK.pinIndex);
        IfxPort_setPinHigh(SCLK.port, SCLK.pinIndex);
    }
}

void send_port(uint8 X, uint8 port)
{
    send(X);
    send(port);
    IfxPort_setPinLow(RCLK.port, RCLK.pinIndex);
    IfxPort_setPinHigh(RCLK.port, RCLK.pinIndex);
}

 


 

결과

아래 SW1을 눌렀을 때 On/Off가 가능하고, 위 SW2를 눌렀을 때 0으로 리셋되는 것을 확인할 수 있다.

4자리 FND 카운터 구현하기 (스위치 제어).gif
11.98MB