최초 수동기어 인디케이터 만들기 글을 올린지가 2009년이었네요.

지금이 2013년이니 4년이 다 되어 갑니다.


지금 올리는 글은 최초 버전에서 조금 더 개선 한 버전으로, 최초 버전 이후 곧 새로 만들기는 했으나 블로그에 포스팅은 하지 않은 회로와 code로 되어 있어 이제서야 글로 올립니다.


상세 내용은 이미 공유 드린 예전 자료를 한번 쭈욱 읽어 주시기 바랍니다.



최초 내용은 AVR을 처음 학습 하던 관계로 무려 MEGA128 모듈을 사용 했습니다만, 이번 내용은 AVR의 좀더 저렴하고 DIY 하기 쉬운 8535L 을 이용하는 내용입니다.

다만 8535L 은 현 시점에 구입이 어려운 관계로, 보드 구성은 MEGA128 모듈을 그대로 사용하시고 Port배치와 chip 간의 차이점을 확인 후 아래 공유 드리는 code를 아주 약간만 수정해서 재사용 가능 하리라 생각 합니다.

추가로 LED에 TR를 달아서 PWM으로 밝기 제어를 해서 최초의 code상 밝기 제어와 비교하여 우수한 표시 안정성을 제공 합니다. 또한 효과도 더욱 멋지게 바뀌었습니다.


회로 구성을 먼저 올리고, 이어서 code를 올려 드립니다.

8MHz 진동자를 사용하는 것을 조심 하셔야 겠습니다.

그래서 16MHz의 모듈을 사용 하신다면 code상에 timing 관련 값을 2배 정도 높여 사용 하셔야 합니다.


상세 내용은 회로도와 code를 보세요. code에 충분한 comment가 달려 있답니다.



[회로도] AVR 8535L 8MHz 진동자와 3.3V LM2576 을 모두 함게 구성 했습니다.

또한 LED 밝기 조절을 위해 A1015 TR하나를 이용한 PWM 제어를 하게 됩니다.




소스코드 파일 다운로드: 

iocompat.h


GearPositionIndicatorLib.h


GearPositionIndicatorLib.c


GearPositionIndicator8535L.c



소스코드 전체 내용

iocompat.h

  1. /*
  2.  * ----------------------------------------------------------------------------
  3.  * "THE BEER-WARE LICENSE" (Revision 42):
  4.  * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
  5.  * can do whatever you want with this stuff. If we meet some day, and you think
  6.  * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
  7.  * ----------------------------------------------------------------------------
  8.  *
  9.  * IO feature compatibility definitions for various AVRs.
  10.  *
  11.  * $Id: iocompat.h,v 1.6.2.1 2008/03/17 22:08:46 joerg_wunsch Exp $
  12.  */
  13.  
  14. #if !defined(IOCOMPAT_H)
  15. #define IOCOMPAT_H 1
  16.  
  17. /*
  18.  * Device-specific adjustments:
  19.  *
  20.  * Supply definitions for the location of the OCR1[A] port/pin, the
  21.  * name of the OCR register controlling the PWM, and adjust interrupt
  22.  * vector names that differ from the one used in demo.c
  23.  * [TIMER1_OVF_vect].
  24.  */
  25. #if defined(__AVR_AT90S2313__)
  26. #  define OC1 PB3
  27. #  define OCR OCR1
  28. #  define DDROC DDRB
  29. #  define TIMER1_OVF_vect TIMER1_OVF1_vect
  30. #elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)
  31. #  define OC1 PB1
  32. #  define DDROC DDRB
  33. #  define OCR OCR1
  34. #elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || \
  35.       defined(__AVR_AT90S4434__) || defined(__AVR_AT90S8535__) || \
  36.       defined(__AVR_ATmega163__) || defined(__AVR_ATmega8515__) || \
  37.       defined(__AVR_ATmega8535__) || \
  38.       defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || \
  39.       defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || \
  40.       defined(__AVR_ATmega1284P__)
  41. #  define OC1 PD5
  42. #  define DDROC DDRD
  43. #  define OCR OCR1A
  44. #  if !defined(TIMSK)           /* new ATmegas */
  45. #    define TIMSK TIMSK1
  46. #  endif
  47. #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega48__) || \
  48.       defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__)
  49. #  define OC1 PB1
  50. #  define DDROC DDRB
  51. #  define OCR OCR1A
  52. #  if !defined(TIMSK)           /* ATmega48/88/168 */
  53. #    define TIMSK TIMSK1
  54. #  endif /* !defined(TIMSK) */
  55. #elif defined(__AVR_ATtiny2313__)
  56. #  define OC1 PB3
  57. #  define OCR OCR1A
  58. #  define DDROC DDRB
  59. #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || \
  60.       defined(__AVR_ATtiny84__)
  61. #  define OC1 PA6
  62. #  define DDROC DDRA
  63. #  if !defined(OCR1A)
  64. #    /* work around misspelled name in avr-libc 1.4.[0..1] */
  65. #    define OCR OCRA1
  66. #  else
  67. #    define OCR OCR1A
  68. #  endif
  69. #  define TIMSK TIMSK1
  70. #  define TIMER1_OVF_vect TIM1_OVF_vect /* XML and datasheet mismatch */
  71. #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || \
  72.       defined(__AVR_ATtiny85__)
  73. /* Timer 1 is only an 8-bit timer on these devices. */
  74. #  define OC1 PB1
  75. #  define DDROC DDRB
  76. #  define OCR OCR1A
  77. #  define TCCR1A TCCR1
  78. #  define TCCR1B TCCR1
  79. #  define TIMER1_OVF_vect TIM1_OVF_vect
  80. #  define TIMER1_TOP 255        /* only 8-bit PWM possible */
  81. #  define TIMER1_PWM_INIT _BV(PWM1A) | _BV(COM1A1)
  82. #  define TIMER1_CLOCKSOURCE _BV(CS12) /* use 1/8 prescaler */
  83. #elif defined(__AVR_ATtiny26__)
  84. /* Rather close to ATtinyX5 but different enough for its own section. */
  85. #  define OC1 PB1
  86. #  define DDROC DDRB
  87. #  define OCR OCR1A
  88. #  define TIMER1_OVF_vect TIMER1_OVF1_vect
  89. #  define TIMER1_TOP 255        /* only 8-bit PWM possible */
  90. #  define TIMER1_PWM_INIT _BV(PWM1A) | _BV(COM1A1)
  91. #  define TIMER1_CLOCKSOURCE _BV(CS12) /* use 1/8 prescaler */
  92. /*
  93.  * Without setting OCR1C to TOP, the ATtiny26 does not trigger an
  94.  * overflow interrupt in PWM mode.
  95.  */
  96. #  define TIMER1_SETUP_HOOK() OCR1C = 255
  97. #elif defined(__AVR_ATtiny261__) || defined(__AVR_ATtiny461__) || \
  98.       defined(__AVR_ATtiny861__)
  99. #  define OC1 PB1
  100. #  define DDROC DDRB
  101. #  define OCR OCR1A
  102. #  define TIMER1_PWM_INIT _BV(WGM10) | _BV(PWM1A) | _BV(COM1A1)
  103. /*
  104.  * While timer 1 could be operated in 10-bit mode on these devices,
  105.  * the handling of the 10-bit IO registers is more complicated than
  106.  * that of the 16-bit registers of other AVR devices (no combined
  107.  * 16-bit IO operations possible), so we restrict this demo to 8-bit
  108.  * mode which is pretty standard.
  109.  */
  110. #  define TIMER1_TOP 255
  111. #  define TIMER1_CLOCKSOURCE _BV(CS12) /* use 1/8 prescaler */
  112. #elif defined(__AVR_ATmega32__) || defined(__AVR_ATmega16__)
  113. #  define OC1 PD5
  114. #  define DDROC DDRD
  115. #  define OCR OCR1A
  116. #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || \
  117.       defined(__AVR_ATmega165__) || defined(__AVR_ATmega169__) || \
  118.       defined(__AVR_ATmega325__) || defined(__AVR_ATmega3250__) || \
  119.       defined(__AVR_ATmega645__) || defined(__AVR_ATmega6450__) || \
  120.       defined(__AVR_ATmega329__) || defined(__AVR_ATmega3290__) || \
  121.       defined(__AVR_ATmega649__) || defined(__AVR_ATmega6490__) || \
  122.       defined(__AVR_ATmega640__) || \
  123.       defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || \
  124.       defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
  125. #  define OC1 PB5
  126. #  define DDROC DDRB
  127. #  define OCR OCR1A
  128. #  if !defined(PB5)             /* work around missing bit definition */
  129. #    define PB5 5
  130. #  endif
  131. #  if !defined(TIMSK)           /* new ATmegas */
  132. #    define TIMSK TIMSK1
  133. #  endif
  134. #else
  135. #  error "Don't know what kind of MCU you are compiling for"
  136. #endif
  137.  
  138. /*
  139.  * Map register names for older AVRs here.
  140.  */
  141. #if !defined(COM1A1)
  142. #  define COM1A1 COM11
  143. #endif
  144.  
  145. #if !defined(WGM10)
  146. #  define WGM10 PWM10
  147. #  define WGM11 PWM11
  148. #endif
  149.  
  150. /*
  151.  * Provide defaults for device-specific macros unless overridden
  152.  * above.
  153.  */
  154. #if !defined(TIMER1_TOP)
  155. #  define TIMER1_TOP 1023       /* 10-bit PWM */
  156. #endif
  157.  
  158. #if !defined(TIMER1_PWM_INIT)
  159. #  define TIMER1_PWM_INIT _BV(WGM10) | _BV(WGM11) | _BV(COM1A1)
  160. #endif
  161.  
  162. #if !defined(TIMER1_CLOCKSOURCE)
  163. #  define TIMER1_CLOCKSOURCE _BV(CS10) /* full clock */
  164. #endif
  165.  



GearPositionIndicatorLib.h

  1. #ifndef __GETPOSITIONINDICATOR_H__
  2. #define __GETPOSITIONINDICATOR_H__
  3.  
  4.  
  5. #define PORT_SEG                        PORTA   // Segment 출력용 port
  6. #define SEG_COMMON_ANODE        1               // Anode 공통 == + 극 공통으로 출력이 0으로 나가야 동작 하는 경우
  7.  
  8. #ifdef  SEG_COMMON_ANODE
  9.         #define SEGOUT(value)   (~value)        // Coommon Anode이므로 bit 상태를 뒤집는다
  10. #else
  11.         #define SEGOUT(value)   (value)
  12. #endif
  13.  
  14.  
  15. unsigned char GetGearPosition( unsigned char state );
  16. char getSegmentData( char currentMode );
  17. void displaySegmentDataNoEffect( char segmentData );
  18.  
  19.  
  20. #endif  // of __GETPOSITIONINDICATOR_H__


GearPositionIndicatorLib.c

  1. /*******************************************************************************
  2.  (C) 2009 Seung-Won Lee   http://whoisit.tistory.com    SoftWareYi@gmail.com
  3.  
  4.  
  5.   수동기어 단수표시 장치
  6.  
  7.   @File  GearPositionIndicator.c
  8. *******************************************************************************/
  9.  
  10. #include <avr/io.h>
  11. #include "GearPositionIndicatorLib.h"
  12.  
  13.  
  14.  
  15. const unsigned char     SEGMENT_MINUS   = 0b10000000;   // -
  16. const unsigned char     SEGMENT_0               = 0b01110111;   // 0
  17. const unsigned char     SEGMENT_1               = 0b00010100;   // 1
  18. const unsigned char     SEGMENT_2               = 0b10110011;   // 2
  19. const unsigned char     SEGMENT_3               = 0b10110110;   // 3
  20. const unsigned char     SEGMENT_4               = 0b11010100;   // 4
  21. const unsigned char     SEGMENT_5               = 0b11100110;   // 5
  22. const unsigned char     SEGMENT_6               = 0b11100111;   // 6
  23. const unsigned char     SEGMENT_7               = 0b01110100;   // 7
  24. const unsigned char     SEGMENT_8               = 0b11110111;   // 8
  25. const unsigned char     SEGMENT_9               = 0b11110110;   // 9
  26. const unsigned char     SEGMENT_BACK    = 0b11111001;   // P. for Back
  27. const unsigned char     SEGMENT_ERROR   = 0b11101011;   // E. for Error
  28. const unsigned char     SEGMENT_H3              = 0b10100010;   // 한자 3
  29. const unsigned char     SEGMENT_ALL             = 0b11111111;   // All for test
  30.  
  31.  
  32.  
  33. //******************************************************************************
  34. // Port로 부터 입력된 기어 위치값으로 부터 현재 기어 위치를 char 문자로 돌려준다
  35. //      중립='N'
  36. //      각 단수='1'~'6'
  37. //      후진:'B'
  38. //      기어조작중:'-'
  39. //      에러상태:'E'
  40. //******************************************************************************
  41. typedef struct
  42. {
  43.         unsigned char   state;
  44.         unsigned char   position;
  45. } stateToPosition;
  46.  
  47. unsigned char GetGearPosition( unsigned char state )
  48. {
  49.         const stateToPosition   stateData[] = {
  50.                 { 0b00100010, 'N' },    // Natural
  51.                 { 0b00010100, '1' },    // 1
  52.                 { 0b01000100, '2' },    // 2
  53.                 { 0b00010010, '3' },    // 3
  54.                 { 0b01000010, '4' },    // 4
  55.                 { 0b00010001, '5' },    // 5
  56.                 { 0b01000001, '6' },    // 6
  57.                 { 0b00011000, 'B' },    // Back
  58.         };
  59.         char    result = '-';
  60.         char    sensingCount = 0;
  61.         unsigned char   i;
  62.  
  63.         state = state & 0b01111111;     // 상위 1bit 사용 안함 처리
  64.        
  65.         // CheckError - 최소한 하나의 bit는 1이어야 정상이다. (실은 2개)
  66.         if ( !(0b01111111 & state) )
  67.         {
  68.                 return 'E';     // 센서로부터 아무런 입력값이 없을 경우 Error처리
  69.         }
  70.  
  71.         // 변속 중인 상태 확인 -> 앞뒤
  72.         sensingCount += ( state & 0b01000000 ) ? 1 : 0;
  73.         sensingCount += ( state & 0b00100000 ) ? 1 : 0;
  74.         sensingCount += ( state & 0b00010000 ) ? 1 : 0;
  75.         if ( sensingCount > 1 ) // 두 위치값이 동시에 입력되면 변동 중인 경우
  76.                 return result;
  77.  
  78.         // 변속 중인 상태 확인 -> 좌우
  79.         sensingCount = 0;
  80.         sensingCount += ( state & 0b00001000 ) ? 1 : 0;
  81.         sensingCount += ( state & 0b00000100 ) ? 1 : 0;
  82.         sensingCount += ( state & 0b00000010 ) ? 1 : 0;
  83.         sensingCount += ( state & 0b00000001 ) ? 1 : 0;
  84.         if ( sensingCount > 1 ) // 두 위치값이 동시에 입력되면 변동 중인 경우
  85.                 return result;
  86.  
  87.         // 모두 통과 되었다면 단수 확인 과정, 확인 불가시 '-' 처리가 default
  88.         for ( i=0; i<sizeof(stateData)/sizeof(stateData[0]); i++ )
  89.         {
  90.                 if ( stateData[i].state == state )
  91.                 {
  92.                         result = stateData[i].position;
  93.                         break;
  94.                 }
  95.         }
  96.  
  97.         return result;
  98. }
  99.  
  100. //******************************************************************************
  101. // getTransmissionValue로 부터 받아진 결과값을 입력하면 포트출력 값을 돌려준다
  102. //******************************************************************************
  103. typedef struct
  104. {
  105.         char    mode;
  106.         char    segmentData;
  107. } modeToSegment;
  108.  
  109. char getSegmentData( char currentMode )
  110. {
  111.         const modeToSegment     modeToSegmentData[] = {
  112.                 { '-', SEGMENT_MINUS }, // -
  113.                 { 'N', SEGMENT_0 },     // 0
  114.                 { '1', SEGMENT_1 },     // 1
  115.                 { '2', SEGMENT_2 },     // 2
  116.                 { '3', SEGMENT_3 },     // 3
  117.                 { '4', SEGMENT_4 },     // 4
  118.                 { '5', SEGMENT_5 },     // 5
  119.                 { '6', SEGMENT_6 },     // 6
  120.                 { 'B', SEGMENT_BACK },  // R == P.
  121.                 { 'E', SEGMENT_ERROR }, // E.
  122.         };
  123.         unsigned char   i;
  124.         char    segmentData = SEGMENT_ERROR;    // Default to Error
  125.  
  126.  
  127.         // 입력값에 대응하는 Segment값을 가져온다
  128.         for ( i=0; i<sizeof(modeToSegmentData)/sizeof(modeToSegmentData[0]); i++ )
  129.         {
  130.                 if ( modeToSegmentData[i].mode == currentMode )
  131.                 {
  132.                         segmentData = modeToSegmentData[i].segmentData;
  133.                         break;
  134.                 }
  135.         }
  136.  
  137.         return segmentData;
  138. }
  139.  
  140.  
  141. void displaySegmentDataNoEffect( char segmentData )
  142. {
  143.         // 일반적인 변동 상황
  144.         PORT_SEG = SEGOUT(segmentData); // Invert for common Anode LED
  145.        
  146. }


GearPositionIndicator8535L.c

  1. /*
  2.   ATMega 8535L 을 이용한 수동기어 인디케이터
  3.  
  4.   기존 ATMEGA128에서 구현한 기능 + PWM 출력을 조절하여 표시 변동시에 부드러운 밝기 변동 처리가 목적
  5.  
  6.   Port A: 7 Segment 출력
  7.   Port C: 포지션 센서 입력
  8.   Port D: PWM 출력을 이용하여 TR을 거쳐서 7 Segment 밝기 조절 처리용으로 사용
  9.  
  10.  
  11.   이전과 같이 Loop의 단순 timing으로 효과 극대화가 곤란
  12.   새로운 구현에서는 밝기 조절은 Timer1을 이용하여 diming 처리
  13.   이어 포지션 변경으 아래와 같은 시나리오롤 처리하자.
  14.  
  15.  
  16.  
  17. */
  18.  
  19.  
  20. #include <inttypes.h>
  21. #include <avr/io.h>
  22. #include <avr/interrupt.h>
  23. #include <limits.h>
  24. #include "iocompat.h"
  25. #include "GearPositionIndicatorLib.h"
  26.  
  27. #define SIZEOF(x) (sizeof(x)/sizeof(x[0]))
  28. #define TIMER0_PWM_RATIO_MAX    4096
  29.  
  30. typedef enum
  31. {
  32.         DIMMING_OFF,
  33.         DIMMING_UP,
  34.         DIMMING_DOWN,
  35.         DIMMING_FLASH,
  36.         DIMMING_CHANGE_ALARM,
  37.         DIMMING_DOWN_FAST,
  38.         _DIMMING_FINISH,
  39.  
  40. } LedDimmingMode;
  41.  
  42.  
  43. static unsigned char LastPinInput = 0xff;               // 이전 입력값
  44. // LED brightness control variables
  45. static char currentDimmingMode = DIMMING_UP;
  46. unsigned char dimmingIndex = 0;
  47. short int brightIndex = 0;              // [0..1] 0 for full power brightness / 1 for >> 1 == /2
  48.  
  49.  
  50. /*
  51.   TCNT1 == Timer/Counter Register (현재 count 값 저장)
  52.                 0되었을 경우 BOTTOM 신호 발생
  53.                 0xFFFF 되었거나 OCR1A/B, ICR1 에 설정된 값에 도달하면 TOP 신호 발생
  54.                   --> BOTTOM / TOP 신호에 의해 카운트를 업/다운 혹은 리셋으로 처리
  55.  
  56.  
  57.   TCCR1AB == Timer/Counter Control Register
  58.  
  59.  
  60.   ICR1 == Input Capture Register
  61.                 입력캡쳐핀 ICx(타이머1의 경우에는 아날로그 비교기의 출력신호도 가능)
  62.                 으로 들어오는 신호변화를 검출하여 일어나는 입력캡쳐시 TCNT1의 카운터 값을 저장하는 16비트 레지스터로
  63.                 이때 ICFx 플랙이 세트되고 입력캡쳐인터럽트가 요청된다. 어떤 신호의 주기 측정에 응용될 수 있다.
  64.  
  65.  
  66.   OCR1AB == Output Compare Register
  67.                 TCNT1 값과 출력 비교되기 위한 16bit data값 저장 / TCNT와 같을경우 OCF 플랙설정, 출력비교 인터럽터 요청,
  68.                 출력핀 OC1A/B 단자로 데이타 출력
  69.  
  70.  
  71.   ICP1 == Input Capture Pin 1: PD6 pin for Timer/Counter1
  72.  
  73.                
  74.   OC1A == 출력핀
  75.   OC1B == 출력핀
  76.  
  77. */
  78.  
  79.  
  80. /*******************************************************************************
  81.  Timer 1 Duty cycle 을 조절하여 LED 발기값을 조절 한다
  82.  [0..256] 받아서, 추가 곱하기 scaling 하여 처리하자
  83. *******************************************************************************/
  84. void SetLedBrightness( int brightness )
  85. {
  86.         brightness = 0xFF - ((brightness & 0xFF)>> brightIndex);
  87.         OCR1A = brightness << 4 | 0x0f;
  88. }
  89.  
  90.  
  91. /*******************************************************************************
  92.  INT0 (PORT D0) - 스위치 입력 처리
  93. *******************************************************************************/
  94. ISR( INT0_vect , ISR_BLOCK )
  95. {
  96. /*      if ( 0 == brightIndex )
  97.                 brightIndex = 1;
  98.         else
  99.                 brightIndex = 0;
  100. */
  101.         if ( ++brightIndex > 2 )
  102.                 brightIndex = 0;
  103.  
  104.         LastPinInput = 0xff;    // 강제로 이전 pin값을 무효화 하여 기어 위치 재출력 로직타게 한다.
  105. }
  106.  
  107.  
  108. /*******************************************************************************
  109.  Timer 0 - 기어 포지션 센서 값 확인 핸들러 주기 설정
  110.  
  111. *******************************************************************************/
  112. void Timer0_Init(void)
  113. {
  114.         // 아래 두 문장은 직접 관련 없는 사항
  115.         DDRB = 0x08;    // Enable output for OC0(PB3)  
  116.         PORTD = 0x00;   // Clear
  117.  
  118.         // Configure Timer/Counter Control Register for 0
  119.         // Fast PWM mode with Clear OC0 on Compare Match, set OC0 at TOP / Clock to No prescaling -> /64 divide
  120.         //TCCR0 = (1<<WGM01) | ( 1<<WGM00) | ( 1<<COM01) | (1<<CS01) | (1<<CS00);
  121.  
  122.         // Normal mode for event looping logic
  123.         // 8MHz 0.125us == 0.000125 ms
  124.         // to /256 then 256*256(count) =
  125.         // to /1024 then 1024*256(count) = 0.000125 * 1024*256 = 32.768 ms = [ 0.032 sec ] * 31 = 0.992 sec ! (31 회 핸들링 시 마다 1초에 가까움)
  126.         //
  127.         // TCCR0 = 0x04;        /256 divide
  128.         //       = 0x05;        /1024 divide
  129.  
  130.         TCCR0 = 0x05;   // Use /1024 divide
  131.         TIMSK = TIMSK | (1<<OCIE0);     // OCR0 match 시에 match intrrupt 발생!
  132.  
  133.         // Output Compare Register - OCR0
  134.         OCR0 = 255;     //126;  //255;  // It's 8 bit!(Max 255)
  135. }
  136.  
  137.  
  138. /*******************************************************************************
  139.  
  140.  확실한 dimming 처리를 위해서는 Timer 1의 16bit 해상도를 사용해야 완전 어두움을 구현 가능!
  141.  밝기 조절은 Timer1 사용
  142. *******************************************************************************/
  143. void Timer1_PWM_Init(void)
  144. {
  145.         //--------------------------------------------------------------------------
  146.         // PortD Pin 4 == OC1B / Pin 5 == OC1A  ==> 00110000 == 0x30
  147.         DDRD = 0x30;    // Enable output for OC1A|OC1B         
  148.         PORTD = 0x00;   // Clear
  149.        
  150.         //--------------------------------------------------------------------------
  151.         // Set TCCR1A/B == Timer/Counter Control Register
  152.         // Fast PWM Mode --> Need WGM13, WGM12, WGM11
  153.         // No prescaling --> CS10
  154.         // /8 prescaling --> CS11
  155.         // Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM
  156.         // Non-Inverting Mode
  157.         TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
  158.         //TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS10);
  159.         TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS11);
  160.        
  161.         // ICR1, TOP Value!
  162.         // Crystal = 4MHz, 0.25us
  163.         // //0.25us * 40000 = 10msec, Frequency = 100Hz
  164.         // ICR1 = 39999;        //40000 - 1
  165.         // //Duty Cycle = 50%, 40000/2
  166.         // OCR1A = 19999;       //20000 - 1
  167.         // //Duty Cycle = 25%, 40000/4
  168.         // OCR1B = 9999;        //10000 - 1
  169.  
  170.  
  171.         //--------------------------------------------------------------------------
  172.         // Crystal = 8MHz -> 0.125us (0.000000125 sec / 0.000125 ms)
  173.         // For 240Hz need 0.0042 ms  / 80000 for 100Hz, 20000 for 400Hz
  174.         //ICR1 = 16384-1;       // 0x4000 2^15  -->> 이 값을 높여 버리면! - 전체적인 밝기 조절이 가능!!!!!!!!!!!!!!!!!!!
  175.         ICR1 = TIMER0_PWM_RATIO_MAX - 1;        // TIMER0_PWM_RATIO_MAX = 4096
  176.         OCR1A = 0;      //TIMER0_PWM_RATIO_MAX - 1;     // OCR1A PWM MAX for dimming, 0 for Max Brightness
  177.         OCR1B = TIMER0_PWM_RATIO_MAX - 1;
  178. }
  179.  
  180.  
  181. /*******************************************************************************
  182. *******************************************************************************/
  183. void Timer1_PWM_Init2(void)
  184. {
  185. /*
  186.         DDRB = 0xff;
  187.         PORTB = ~0x08;
  188. //      PORTB = 0x00;
  189.  
  190.         TCCR1A = TIMER1_PWM_INIT;
  191.         TCCR1B = TIMER1_CLOCKSOURCE;
  192.  
  193.         OCR0 = 0;
  194. */
  195. }
  196.  
  197.  
  198. /*******************************************************************************
  199.  
  200. *******************************************************************************/
  201. void Timer2_Init(void)
  202. {
  203.         // Normal mode for event looping logic
  204.         // 8MHz 0.125us to /1024 then 1024*88(count) = 11Hz
  205.         TCCR2 = 0x07;   // /1024  [CS2,CS1,CS0] = 111
  206.         TIMSK = TIMSK | (1<<OCIE2);     // OCR2 match 시에 match intrrupt 발생!
  207.  
  208.         // Output Compare Register - OCR0
  209.         OCR2 = 255;     // COMP 핸들러에서 TCNT2를 0 으로 초기화하여 fine tunning 값으로 사용
  210. }
  211.  
  212.  
  213. /*******************************************************************************
  214.  Interrupt vector for Timer 0 overflow signal
  215.  
  216. *******************************************************************************/
  217. /*ISR( TIMER0_OVF_vect, ISR_BLOCK )
  218. {
  219.         // 아직 활성화 하지 않음.
  220. }*/
  221.  
  222.  
  223. //******************************************************************************
  224. // getTransmissionValue로 부터 받아진 결과값을 입력하면 포트출력 값을 돌려준다
  225. //******************************************************************************
  226. void SetLedDimming( LedDimmingMode mode )
  227. {
  228.         currentDimmingMode = mode;
  229.         dimmingIndex = 0;
  230.         // 위 설정값은 TIMER2_COMP_vect 에서 처리함.
  231. }
  232.  
  233.  
  234. //******************************************************************************
  235. // Gear위치를 LED로 출력
  236. //******************************************************************************
  237. void SetLedDisplayChar( char gearPosition )
  238. {
  239.         displaySegmentDataNoEffect( getSegmentData( gearPosition ) );
  240. }
  241.  
  242.  
  243. /*******************************************************************************
  244.  Control LED dimming effects
  245.  LED 밝기값을 시나리오별로 조절하는 역할을 한다.
  246.  
  247.  현재 대충~ 30 회당 1초로 확인 됨. // 100회당 3.3 초
  248.  --> 10회당 1초로 할까?  --> 이게 만만해 보임 좀 버번 거리게 보일 수도...
  249.  --> 100회당 1초로 할까? --> 100Hz > 좀 부하가 있을 느낌
  250. *******************************************************************************/
  251. //typedef struct
  252. //{
  253. //      unsigned char   index;                  // 0 then stop the effect progressing
  254. //      unsigned char   brightness;             // -1 then restart the effect - it reset dimmingIndex
  255. //} indexToBrightness;
  256.  
  257. ISR( TIMER2_COMP_vect, ISR_BLOCK )
  258. {
  259.         const int                       // 1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20
  260.                 dimmingUpTbl[] =        { 20,  40,  60,  80, 100, 150, 200, 255, 255, 255,  -1,  -1 };
  261.         const int
  262.                 dimmingDownTbl[] =      {200, 200, 190, 180, 170, 160, 150, 140, 130, 120, 110, 100,  90,  80, 75,  70,  65,  60,  55,  50,
  263.                                                           45,  40,  35,  30,  27,  24,  21,  19,  18,  17,  16, -1,  -1 };
  264.         const int
  265.                 dimmingFlashbl[] =      {255, 255, 200, 160, 100,  30,   0,   0, 120, 250,  -2 , -2 };
  266.         const int
  267.                 dimmingChangeAlarmTbl[] =
  268.                                                         {255,   0, 255,   0, 255, 200, 150, 100,  50, 100, 150,200, 250, 200, 170, 200, 255,  -1,  -1 };
  269.         const int
  270.                 dimmingDownFastTbl[] =
  271.                                                         {100, 100, 180, 255, 200, 150, 100,  70,  50,  30,  20, 10,  0,   -1,  -1 };
  272. //      static unsigned char  flash = 0;                // For debugging
  273.         static unsigned char  ISRdelay = 0;
  274.         int     brightness;
  275.  
  276.         ++ISRdelay;
  277.         if ( ISRdelay < 3 )
  278.                 return;
  279.         else
  280.                 ISRdelay = 0;
  281.  
  282.  
  283.         TCNT2 = 0;      // Timer reset for resolution tunning
  284.  
  285.         //__________ 디버깅용 LED 깜빡임
  286. //      ++flash;
  287. //      if ( 5 == flash )
  288. //              PORTB = PORTB | 0x01;
  289. //      else if ( 10 == flash )
  290. //      {
  291. //              PORTB = PORTB & ~0x01;
  292. //              flash = 0;
  293. //      }
  294.         //^^^^^^^^^^
  295.  
  296.         brightness = 0;
  297.         switch ( currentDimmingMode )
  298.         {
  299.         case DIMMING_OFF:               // Just turn off the LED
  300.                 SetLedBrightness( 0 );
  301.                 currentDimmingMode = _DIMMING_FINISH;
  302.                 dimmingIndex = 0;
  303.                 return;
  304.                 break;
  305.  
  306.         case DIMMING_UP:
  307.                 brightness = dimmingUpTbl[dimmingIndex];
  308.                 if ( -1 == brightness )                                         // -1 to finish effect scenario
  309.                 {
  310.                         currentDimmingMode = _DIMMING_FINISH;
  311.                         dimmingIndex = 0;
  312.                         return;
  313.                 }
  314.                 break;
  315.  
  316.         case DIMMING_DOWN:
  317.                 brightness = dimmingDownTbl[dimmingIndex];
  318.                 if ( -1 == brightness )                                         // -1 to finish effect scenario
  319.                 {
  320.                         currentDimmingMode = _DIMMING_FINISH;
  321.                         dimmingIndex = 0;
  322.                         return;
  323.                 }
  324.                 break;
  325.  
  326.         case DIMMING_FLASH:
  327.                 brightness = dimmingFlashbl[dimmingIndex];
  328.                 if ( -2 == brightness )                                         // -2 to repeat the effect
  329.                 {
  330.                         dimmingIndex = 0;
  331.                         return;
  332.                 }
  333.                 break;
  334.  
  335.         case DIMMING_CHANGE_ALARM:
  336.                 brightness = dimmingChangeAlarmTbl[dimmingIndex];
  337.                 if ( -1 == brightness )                                         // -1 to finish effect scenario
  338.                 {
  339.                         currentDimmingMode = _DIMMING_FINISH;
  340.                         dimmingIndex = 0;
  341.                         return;
  342.                 }
  343.                 break;
  344.  
  345.         case DIMMING_DOWN_FAST:
  346.                 brightness = dimmingDownFastTbl[dimmingIndex];
  347.                 if ( -1 == brightness )                                         // -1 to finish effect scenario
  348.                 {
  349.                         currentDimmingMode = _DIMMING_FINISH;
  350.                         dimmingIndex = 0;
  351.                         return;
  352.                 }
  353.                 break;
  354.  
  355.         case _DIMMING_FINISH:
  356.                 currentDimmingMode = _DIMMING_FINISH;
  357.                 return; // 더 이상 counting 하지도, 동작 수정 안함.
  358.                 break;
  359.         }
  360.  
  361.         SetLedBrightness( brightness );
  362.         ++dimmingIndex;
  363. }
  364.  
  365.  
  366. /*******************************************************************************
  367.  
  368. *******************************************************************************/
  369.  
  370.  
  371. /*******************************************************************************
  372.  Interrupt vector for Timer 0 compare matching
  373.  기어 센서 상태값을 확인하고, 전환 시나리오별로 처리 한다.
  374. *******************************************************************************/
  375. #define TIMEOUT_TO_1SEC (31)            // 30은 1분 이하로 오차 발생, 31이 좀더 근접하나 상세 TUNING을       tcnt0 를 통할 필요 있음
  376.  
  377. ISR( TIMER0_COMP_vect, ISR_BLOCK )
  378. {
  379.         //__________ 디버깅용 LED 깜빡임
  380.         {
  381.                 static char  flash = 0;
  382.                 if ( ++flash > TIMEOUT_TO_1SEC )
  383.                 {
  384.                         flash = 0;
  385.                         PORTB ^= 0x01;
  386.                 }
  387.         }
  388.         //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  389.  
  390.  
  391.  
  392.         // Timer 해상도를 좁히기 위해 OCR0 값을 설정하고, 이 code를 활성화 하고 값을 높이면 timer 분주를 빨리함 (시작 카운트 값 설정)
  393.         TCNT0 = 3;
  394.         {
  395.                 static char LastGearPosition = '-';                                     // 이전 기어 상태 (LastPinInput으로 부터 변환된 값)
  396.                 static unsigned long int InputChangeTimeCount = 0;      // 기어 변속 이후 경과시간 - 0: Timer 중지, 1~ Counting 계속
  397.                 static unsigned long int IdleTimeCount = 0;                     // Idle time 경과시간 - 0: Timer 중지, 1~ Counting 계속
  398.  
  399.  
  400.                 unsigned char NewPinInput = ~PINC & 0x7f;                       // 현재 Pin 값 받기
  401.                 unsigned char NewGearPosition = GetGearPosition( NewPinInput ); // Gear 위치값으로 환산
  402.  
  403.                 if ( LastPinInput != NewPinInput )              // 센서 입력 변동?
  404.                 {//----- 센서 변동 -----------------------------------------------------
  405.                         LastPinInput = NewPinInput;                     // 이전값 갱신
  406.                         InputChangeTimeCount = 1;                       // 변동 시간 count 시작
  407.                         IdleTimeCount = 0;                                      // Idle time count 중지
  408.  
  409.                         switch ( NewGearPosition )
  410.                         {
  411.                                 case '-' :      // 기어 전환중, 중립상태 시나리오
  412.                                 case 'N' :      // 다른 기어로 전환이 곧 될 수 있기에 Dimming처리고 어둡게 함
  413.                                         // 0~6 에서
  414.                                         if ( '-' != LastGearPosition )                  // 이전엔 기어위치였으나, 전환 하려는 경우임
  415.                                         {
  416.                                                 SetLedDimming( DIMMING_DOWN );          // 천천히 어두워 지게 함
  417.                                                 LastGearPosition = NewGearPosition;     // 기어값만 갱신
  418.                                                                                                                         // 변동 시간 count 계속 동작하게 둠. 0 상태에서 에니메이션 시나리오 가능케 함
  419.                                                                                                                         // LED 표시는 수정하지 않음
  420.                                         }
  421.                                         break;
  422.  
  423.                                 case 'E' :      // 입력 에러E / 후진(B)시는 즉각적으로, 또한 깜빡임 처리
  424.                                 case 'B' :
  425.                                         LastGearPosition = NewGearPosition;             // 마지막 기어 위치값 갱신
  426.                                         SetLedDisplayChar( NewGearPosition );   // LED 표시 갱신
  427.                                         InputChangeTimeCount = 0;                               // 변동 시간 count 중지 -> 무변동 상테에서 시나리오 멈춤
  428.                                         SetLedDimming( DIMMING_FLASH );                 // 반복적인 깜빡임
  429.                                         break;
  430.  
  431.                                 default:        // 나머지 기어값인 1 ~ 6 의 경우 기어 위치 확정 표시
  432.                                         LastGearPosition = NewGearPosition;             // 마지막 기어 위치값 갱신
  433.                                         SetLedDisplayChar( NewGearPosition );   // LED 표시 갱신
  434.                                         InputChangeTimeCount = 0;                               // 변동 시간 count 중지 -> 무변동 상테에서 시나리오 멈춤
  435.                                         SetLedDimming( DIMMING_CHANGE_ALARM );  // 깜빡이면서 밝게 표시
  436.                                         break;
  437.                         }
  438.                 }
  439.                 else
  440.                 {//----- 변화가 없는 경우 ----------------------------------------------
  441.                         // '-' 혹은 '0' 가 계속 유지 되고 있다면 특정 시간 이후에 '-' / '0'을 표시한다
  442.  
  443.                         //----- 기어 변경 후 일정 시간 지남 확인 카우트 동작 진행
  444.                         if ( InputChangeTimeCount )
  445.                         {
  446.                                 // 0 표시는 즉각적으로 갱신하지 않고, 1초간 대기 후 갱신한다.
  447.                                 // 왜냐면 기어 변속중에 항상 0 위치를 거치게 되므로 잦은 갱신을 하지 않아 자연스럽게 다음 기어를 표시하게 된다.
  448.  
  449.                                 //----- N(중립) 에서 1초 초과시에 진짜 N(0)으로 표시 갱신
  450.                                 if ( ('N' == NewGearPosition) && (InputChangeTimeCount > 1*TIMEOUT_TO_1SEC) )
  451.                                 {
  452.                                         InputChangeTimeCount = 0;                               // 이후 Timer 작동 중지
  453.                                         IdleTimeCount = 1;                                              // Idle time count 시작 -> Idle animation 처리 용
  454.                                         LastGearPosition = NewGearPosition;             // 기어 포지션 갱신
  455.                                         SetLedDisplayChar( NewGearPosition );   // LED 표시 갱신
  456.                                         SetLedDimming( DIMMING_CHANGE_ALARM );  // 깜빡이면서 밝게 표시
  457.                                 }
  458.                                 //----- 기어 이동중(기어 물림 위치가 아닌경우)이라면 3초간 기존 상태 유지(위에서 dimming down) 후, 새값으로 갱신
  459.                                 else if ( ('-' == NewGearPosition) && ( InputChangeTimeCount > 3*TIMEOUT_TO_1SEC ))
  460.                                 {
  461.                                         InputChangeTimeCount = 0;                               // 이후 Timer 작동 중지
  462.                                         //IdleTimeCount = 1;                                    // Idle time count 시작 X
  463.                                         LastGearPosition = NewGearPosition;             // 기어 포지션 갱신
  464.                                         SetLedDisplayChar( NewGearPosition );
  465.                                         SetLedDimming( DIMMING_UP );                    // 천천히 밝게 표시
  466.                                 }
  467.                                 else
  468.                                 {
  469.                                         if ( ++InputChangeTimeCount >= ULONG_MAX )      // Counting
  470.                                                 InputChangeTimeCount = 0;                       // Overflow 시에 더이상 이어변동 후 타이머 동작은 작동 안함.
  471.                                 }
  472.                         }
  473.                         //----- 이어 변경 직후 타이밍 동작 완료 후, Idling 상태에서 0 위치에서 animation 표시 등 부가 동작 수행
  474.                         else
  475.                         if ( IdleTimeCount && 'N' == NewGearPosition )
  476.                         {       // 0 상태에서 장시간 대기중일 경우 Rotation animation 처리하기~
  477.                                 const char segmentAnimationData[] = {           // 오른쪽으로 회전하는 에니메이션에 해당한 segment LED 출력 bit
  478.                                         0b01000000,     // 0b01000100,
  479.                                         0b00100000,     // 0b00100010,
  480.                                         0b00010000,     // 0b00010001,
  481.                                         0b00000100,     // 0b01000100,
  482.                                         0b00000010,     // 0b00100010,
  483.                                         0b00000001,     // 0b00010001,
  484.                                 };
  485.  
  486.  
  487.                                 //----- 30초 초과시 부터 idle animation시작
  488.                                 if ( IdleTimeCount >= 30*TIMEOUT_TO_1SEC )
  489.                                 {
  490.                                         static unsigned char prevAniIndex = 6;
  491.                                         char bDisplayIdleMinTime = 0;
  492.                                         unsigned char aniIndex = ( (IdleTimeCount - 1 ) / TIMEOUT_TO_1SEC ) % 6;
  493.                                         unsigned char i;
  494.  
  495.  
  496.                                         //----- {{110723 lsw2000}} 1분, 2분, 3분, 최고 6분 까지에 대해 Idle 경과 시간 표시! / 웜업, 후열용 참고 시간 표시
  497.                                         if ( IdleTimeCount < (6*60 +10) *TIMEOUT_TO_1SEC )
  498.                                         {
  499.                                                 for ( i=1; i<=6; i++ )
  500.                                                         if ( i*60*TIMEOUT_TO_1SEC <= IdleTimeCount &&IdleTimeCount < (i*60 +(4+i)) *TIMEOUT_TO_1SEC )          // 최초 4초부터 1초식 증가하여 표시
  501.                                                         {
  502.                                                                 if ( i*60*TIMEOUT_TO_1SEC == IdleTimeCount )    // 숫자 전화, 효과 설정은 단 1회만, 이후 자동
  503.                                                                 {
  504.                                                                         SetLedDisplayChar( '0' + i );                           //
  505.                                                                         SetLedDimming( DIMMING_FLASH );                         // 반복적인 깜빡임
  506.                                                                 }
  507.                                                                 bDisplayIdleMinTime = 1;
  508.                                                         }
  509.                                         }
  510.                                         else
  511.                                         //----- 7분 경과부터 매 1분 마다 0 표기 깜빡이기
  512.                                         if ( (7*60) *TIMEOUT_TO_1SEC <= IdleTimeCount )
  513.                                         {
  514.                                                 if ( IdleTimeCount % (60*TIMEOUT_TO_1SEC) < (5*TIMEOUT_TO_1SEC) )      // 매붖 최초 5초 동안
  515.                                                 {
  516.                                                         if ( 0 == IdleTimeCount % (60*TIMEOUT_TO_1SEC) )
  517.                                                         {
  518.                                                                 SetLedDisplayChar( 'N' );
  519.                                                                 SetLedDimming( DIMMING_FLASH );                         // 반복적인 깜빡임
  520.                                                         }
  521.                                                         bDisplayIdleMinTime = 1;
  522.                                                 }
  523.                                         }
  524.                                        
  525.                                         //----- 경과 분수 표시 타이밍이 아닌 경우 animation 표시
  526.                                         if ( !bDisplayIdleMinTime && ( prevAniIndex != aniIndex ) )
  527.                                         {
  528.                                                 prevAniIndex = aniIndex;
  529.                                                 PORT_SEG = ~segmentAnimationData[ aniIndex ];   // ~for Negative output
  530.                                                 SetLedDimming( DIMMING_DOWN_FAST );                             // 새 위치 표시 후 어두워지게 효과 처리
  531.                                         }
  532.                                 }
  533.  
  534.                                 if ( ++IdleTimeCount >= ULONG_MAX )                             // Overflow 대비, animation 계속하게 함.
  535.                                         IdleTimeCount = 30*TIMEOUT_TO_1SEC;
  536.                         }
  537.                         // TODO: 기어 상태에서 장시간 있을 경우 살짝 깜빡임성 표시로 환기 시키기
  538.                 }
  539.  
  540.         }
  541.  
  542.  
  543. }
  544.  
  545. /*******************************************************************************
  546.  Main enterance
  547.  
  548. *******************************************************************************/
  549. int main( void )
  550. {
  551.         cli();
  552.  
  553.         Timer0_Init();          // 노브 조작 감지(센서 감지 루프)
  554.         Timer1_PWM_Init();      // PWM ouput 조작
  555.         Timer2_Init();          // 깜빡임, 밝기 시나리오 흐름
  556.  
  557.         //----- INT0 ----------
  558.         GICR |= 1<<INT0;        // INT0 enable
  559.         MCUCR = 2;                      // 하강엣지에 인트럽트 발생
  560.  
  561.         DDRA = 0xFF;            // PortA: 출력 / 7 Segment
  562.         DDRB = 0xFF;            // PortB: Timer and Debug signal
  563.         DDRC = 0x00;            // PortC: 입력 / 기어 포지션 센서
  564.         //DDRD = ~0x04;         // PortD2(INT0) 입력 활성화
  565.  
  566.         PORT_SEG = 0xFF;        // Common anode 이므로 1상태가 off 가 된다
  567.         PORTB = 0xFF;           // + 인가
  568.         PORTC = 0xFF;           // Input port에 1을 setting하여 Internal pull-up 저항을 활성화
  569.         PORTD = 0x04;           // PD2(INT0) Pull-up
  570.  
  571.  
  572.         sei();                          // 주 동작은 Timer handler에서 수행 됨.
  573.         // Timer0: Main loop
  574.         // Timer1: PWM power 조절
  575.         // Timer2: LED 깜빡인 control
  576.  
  577.         SetLedBrightness(10);   // First Full brightness.
  578.  
  579.         while ( 1 )
  580.         {
  581.  
  582.         }
  583.  
  584.         return 0;
  585. }



.



르노삼성 [QM5 가격표(<클릭!)]를 만들어 공유 합니다.



본 내용이 도움 되셨다면 아래 버턴 꾸~욱 눌러 주세요


수정내역
 2012-12-20: 2012년 11월 가격표 반영
 2012-07-03: 2013년형 QM5 가격표 반영
 2011-07-01: NEW QM5 가격표 반영
 2011-02-02: SE Premium Package 트림 추가
 2010-07-02: 2011년식 변동 반영 
 2010-01-04: 2010년식 변동 반영(세부 옵션 삭제,추가,변경, FAIRWAY->LE Plus)
 2009-09-02: 트림 변동 반영(트림 종류 축소, 수동모델 단종(스포티), FAIRWAY 신규 출시)
 2009-07-08: 개별소비세 환원으로 이한 가격 변경 사항 반영
 2009-04-01: 09년 4월 변경된 사양(6CDC MP3) / ADVENTURE 트림 반영
 2009-01-14: 한시적 개별소비세(특별소비세) 인하에 따른 가격표 수정 사항 반영



아래는 2012년 7월 변경 정리 입니다.


상품성 개선 사항을 종합하면 아래와 같습니다.

  * 실버 스키드(앞/뒤, LE이상 기본장착)

  * 사이드&커튼 에어백 시스템(LE이상 기본장착)

  * 운전석/동승석 파워시트(RE기본)

  * 브라운 패키지(가죽시트,대시보드,스티어링휠,티타늄 크롬&골드 그레이)


대신 트림별로 이전에 비해 제외된 사양이 적지 않습니다. (가격표에서 확인된 사항)


SE

  +50,000 원 인상

  -앞면 차음 글라스 (전체?!)

  +글로브 박스 냉장기능

  -이동식 재떨이 (SE만)

  -오토라이팅 헤드램프 (SE만)

  -레인센싱 와이퍼 (SE만)


LE

  +50,000 원 인상

  +사이드/커튼 에어백 


LE Plus 

  +45,000 원 인상 (가솔린 -160,000 원!(인하))

  v웨이브 그레인

  -전좌석 세이프티 파워윈도우 (전체?!)

  -컨버세이션 미러 (전체?!) 


RE 

  +50,000 원 인상 (가솔린 -160,000 원!(인하))

  -러기지 스크린



아래는 2011년 7월 변경 정리 입니다. - 부분 변경 모델인 NEW QM5 출시가 되었습니다.

변동사항 종합하면 아래와 같습니다.
  * 디젤 2.0 2WD 173마력 36.7토크로 업그레이드 [이미 단종된 4WD 고마력 버전(스포티)와 동일 출력
  - 블루이쉬실버 색상 단종       + 메이플 레드, 마르스 그레이 추가
  v Bose 에디션 대신 LE+ 로 환원, SE 기준 65만원 인상
  + VDC 전모델 기본 탑제         - B-LSD 삭제
  + 급제동경보시스템(ESS)      + 내스크래치 클리어도장,
  + 기본 프로젝션 헤드램프      + 후방 안개등
  + LED 방향지시등 일체형 아웃사이드미러,  +원터치 트리플 턴 시그널
  + USB/iPod연결단자(AUX 포함) 기본사양

-전트림 삭제 사양
  도어커티시램프(뒤) 삭제 되었습니다.
  콘솔박스 조명 삭제 되었습니다(이전: Bose/LE Plus 부터 조명장착)

[+추가 / -삭제, 윗 트림에 누적사항임]
SE 변동사항    
   * 650,000 원 인상
  +차체자세 제어장치(VDC) 
  -전륜 차동제한장치(B-LSD)
 
 +급제동경보시스템(ESS)
  +내스크래치 클리어도장 
  +프로젝션 헤드램프 
  +후방 안개등
  +LED 방향지시등 일체형 아웃사이드미러 
  v화이트 조명
  +원터치 트리플 턴 시그널
  +USB/iPod연결단자(AUX 포함) 
 
LE 변동사항 (SE 변동사항에 누적하여 아래 사항이 변동)
  +500,000 원 인상
  -LE 전용 17" 알로이 휠(SE동일)
  -선바이저 조명
  -도어커티시램프(뒤)
  -인텔리전트 스마트카드 시스템
  -전좌석 세이프티 파워윈도우 
  -운전석 파워시트 
  
LE Plus 변동사항 (LE 변동사항에 누적)
  +200,000 원 인상
  +다기능 센터콘솔박스
  +원-액션 더블폴딩 2열시트

RE 변동사항
  +500,000 원 인상 (실제 610,000 원 인상 효과: Bose기본에 반해 파노라마 선루프 삭제 차이가 11만)
  -파노라마 선루프
  +Bose® 사운드시스템


*4WD는 기존 마력과 동일하고, LE 트림의 경우 여러 옵션이 대거 빠져서 LE라기 보다는 SE+가 어울릴 듯한 상품 구성으로 보입니다.
*상세 내용은 가격표를 참고 하세요



아래는 2011년 2월 변경 정리 입니다. - 2011년과 동일하며 SE Premium Package 트림만 추가.

SE 등급에 상품성을 더해 주는 패키지 모델이 추가 되었습니다.
기본적으로 SE 트림에 아래의 사양이 추가 되었습니다.
+가죽시트
+가죽커버(스티어링 휠/변속기 노브)
+앞좌석 도어수납함
+후방 경보장치

디젤 기준 SE 대비 +80 만원
가솔린 기준 SE 대비 +84만원 



아래는 2010년 7월 변경 정리 입니다. - 2011년형 QM5 입니다.

VDC+TPMS 가격 인하로 안전옵션 선택시 실질적인 가격 하락입니다(RE는 비싸졌습니다)
디젤모델 연비가 1km/ℓ 이상 향상 되었습니다 - 현기차의 공인연비 향상 기술(?)을 가져왔는지 모르겠습니다 ㅋ~

주요 변동사항
* 디젤모델 연비 향상: 2WD 기존 12.8km/ℓ > 13.8km/ℓ, 4WD 모델은 12.2km/ℓ > 13.4km/ℓ
* LE+ 대신 BOSE special edition이 출시 되었습니다.
* 4WD모델에 SE 그레이드가 추가 되었습니다.
* 디젤모델의 경우 유로5 인증 되었습니다.
v 라디에이터 그릴의 블랙부분을 실버페인트 처리하였습니다(이미 DIY 아이템이었습니다)
+ 전 모델에 크루즈 컨트롤&스피드 리미터가 장착 되었습니다(힘들게 DIY 하실 필요가 없네요)

+개선내용
  VDC+TPMS 가격 인하되어 2WD 55만, 4WD 70만, 가솔린 58만원 (기존대비 37만, 39만 인하)

-전트림 삭제 사양
  글로브박스 잠금 기능이 삭제 되었습니다.
  시트언더 트레이 삭제 되었습니다.

가격변동 [기본사양 기준]
  디젤:  SE: +19만 / LE: +20만 / BOSE: +40만 / RE: -50만(BOSE 포함시 +25만) 
  가솔린: SE25: +9만 / LE25: +10만 / BOSE25: +30만 / RE25: -60만(BOSE포함시 +19만)
  
SE 변동사항 [+추가 / -삭제, 윗 트림에 누적사항임]
  +크루즈 컨트롤&스피드 리미터
  +라디에이터 그릴의 블랙부분을 실버페인트 처리
  -글로브박스 잠금 장치

LE 변동사항 (SE 변동사항에 누적하여 아래 사항이 변동)
  -조수석 시트언더 트레이
  
BOSE (기존 LE Plus급)변동사항
  +BOSE 특화 옵션 (휠, 앰플럼, 청공+그레이 스티치 가죽시트, 그레이 라운딩 카매트, 전용 키킹플레이트 등)
  -전방 경보장치
  -러기지 스크린
  -원액션 더블폴딩 2열시트
  v18인치 휠 선택 불가(BOSE 전용휠 채택)
  v카본파이버 대신 메탈릭 그레인 적용

RE 변동사항
  -BOSE 사운드 시스템 별도 옵션 선택화 (75만원)



아래는 2010년 1월 변경 정리 입니다.
[공식 가격표에 나와 있는 명세서 내용을 비교 했습니다. 혹시 틀린 부분은 알려주세요]
FAIRWAY는 단종되고, LE Plus로 환원 되었습니다. 단 4WD모델에는 LE, RE 만 유지 됩니다.

VDC+TPMS 전트림 선택 가능하게 조건이 좋아졌습니다.
  VDC(차체자세 제어장치), TPMS(타이어공기압 자동감지 시스템)

가격변동
이 있습니다. (역시 RE를 사야만 하는지...)
  SE,LE: +10만 / LE Plus: +15만 / RE: +2만 / RE25: + 8만

삭제된 사양은 아래와 같습니다 [전 트림에서 삭제 되거나 변경]
  틸트헤드레스트 (LE이상 기본 적용)
  인대쉬 6CDC오디오 (약 20만원 사양)
  4WD 인포테인먼트 (약 10만원 사양)
  기존 SE전용 휠
  베이지투톤 시트(FAIRWAY용)

추가된 사양은 아래와 같습니다.
  크롬장식 콤비미터링, 크롬장식 에어벤트 커서, 하이그로시 블랙 장식, 카본파이버 그레인,
  하이패스, 블루투스 MP3CDP, USB & i-Pod연결단자(Aux포함),
  알카미스(Arkamys 3D) 사운드 시스템,
  스마트i내비게이션(선택시, USB 단자 삭제)

SE 변동사항 [+추가 / -삭제, 윗 트림에 누적사항임]
  +루프스포일러 기본 장착(전 트림) (약 16만원 사양)
  +크롬장식 콤비미터링(전 트림)
  +MP3CDP
  -인대쉬 6CDC 삭제
  -다이버시티 글라스안테나

LE 변동사항 (SE 변동사항에 누적하여 아래 사항이 변동)
  +알카미스 3D 사운드
  -틸트 헤드레스트(앞좌석)
 
LE Plus 변동사항
  +하이패스 시스템
  v Bose 사운드 시스템 (기존 FAIRWAY 적용 유지)

RE 변동사항
  +하이그로시 블랙장식
 


아래는 2009년 9월 변경 정리 입니다.
추가 모델 FAIRWAY가 등장 했습니다.
  기본 사양은 기존의 LE+사양과 유사한 등급이라고 볼 수 있습니다.(전자식 파킹브레이크, 컨버세이션 미러)
  다만 내외부에 차별을 조금씩 주어 기존 QM5 선택에 식상했다면 조금 나아 보입니다.
  특히 18인치 휠,타이어를 선택 가능하게 한 것이 특이점입니다.

트림 축소로 아래 트림은 삭제 되었습니다.
  SE, LE Plus, 스포티


스포티 단종 ( LE Plus급 4WD 수동 173마력 )
결과적으로 QM5 에서 수동 모델은 더 이상 구입할 수 없게 되었습니다.
스포티 소유자로서 매우 아쉽습니다. 겨우 1년간 판매된 모델로 한국에서는 매우 적어 수만이 존재를 하게 되었습니다. 참고로 2009년 부터 SE 수동을 단종을 했었고, 09년 09월 부터는 유일한 수동인 스포티도 단종입니다.

SE Plus 변동사항
  스티어링 휠 텔레스코픽 기능 삭제
  가격 30만원 상향

LE 변동사항
   기존 LE Plus 사양이 대폭 적용되었으나 LE Plus에 있던 대표적인 사양인 전자식주차브레이커는 미적용
  가격 약 30만원 상향으로 분석

RE 변동사항
  기본 가격은 증가했으나 세이프티패키지(VDC+TPMS)가 기본 사양에 포함되어
  실질적으로 가격 인하가 되었음.

RE모델의 경우 가격하락입니다. 나머지 모델은 상승되었습니다. 기존 LE Plus급의 사양을 원하시는 분들께서는 약간의 부담이 더 있더라도 RE 모델을 선택하시는게 더 유용하다고 보입니다.

 

아래는 2009년 4월 사양 변경 정리 입니다.

6CDC MP3 오디오가 기본 장착 되었습니다. (전모델/RE는 기본으로 Bose)
이로인해 +20만 상향 되었습니다.
단 기존 Bose 옵션 없이 MP3가 가능하고, Bose 옵션의 경우 -20만 되었습니다.
추가된 사양:  루프안테나/인대시 6CD 체인저/MP3&WMA 재생기능/다이버시티 글라스안테나

신규 트림 추가: ADVENTURE
기본사양은 LE와 동일하며 가격은 LE+와 같습니다.
추가 사양으로 - 파노라마 썬루프, 스키드셋3 이 기본 사양으로 채택
  스키드셋3: 실버스키드(프론트/리어), 바디키트, 루프 스포일러, 머플러 디퓨저

4WD 모델에 4WD 인포테인먼트가 기본으로 포함
09년식에서 Bose 선택시에 2WD 보다 추가로 +10만원 했던 내용이 없어져서 - 결국 LE 4WD모델은 가격이 -10만원 되었습니다. (헉! 저는 10만원 더 주고 샀는데 ㅠ.ㅠ)



아래는 2009년형 변경 사항 정리 입니다 (2008년 8월 출시분)

2008년 형 대비 기본 품목에서 완전히 사라진 사양도 있고, 기존의 Option사양이 기본 포함된 사양도 있습니다.

모든 트림에 대해서 블랙 내장제 적용을 하여 LE트림의 베이지 색상 때에 대한 두려움을 없앨 수 있을 듯 합니다.

** 트림 종류가 축소 되었습니다.
 > 기존(2008MY):
           SE, SE Plus,
           LE, LE Plus, LE Premium,
           RE, RE Plus

 > 변경(2009MY):
           SE, SE Plus,
           LE, LE Plus,
           RE

    LE Plus가 기존 LE Premium화 했습니다, RE는 RE Plus화 했습니다. - 상세 변동은 아래 내용 참조.


** 전트림 완전 삭제 항목 추가 했습니다
 > 2008-07-11 : 운전석 사이드 미러 2-Way기능
 > 2008-07-14 : 조수석 시트 폴딩

전트림 완전 삭제 항목은 아래와 같습니다. 상세 내용은 [이전 글]을 참고 하세요.
- 운적석 아웃사이드 미러의 2-Way 기능  (사각지역을 보여주는 기능인데 어지럽다는 의견이 많았답니다)
- 조수석 시트 폴딩 [LE Plus]  (여러 사용자 불만 해결을 위해?: 뒤로 제쳤을 때 허리가 들려 불편)
- B-필러 에어벤틸레이션 [LE Primium]
- 리어도어 선블라인드 [LE Primium]
- 플로어 언더보관함 [RE]
- 3-WAY 트렁크 네트

트림별 추가(옵션 확장) 항목은 아래와 같습니다.
+ SE: 바디컬러 스키드 (<-LE)
+ SE: 안개등 (<-SE Plus)
+ SE: 2열 시트 각도조절 (<-LE Plus)
+ LE: 후방 경보장치 (<-LE Plus [전방은 LE Plus 부터])
+ LE: 실버페인트 루프랙 (Option 16만)
+ LE: 가죽시트 (<-LE Primium)
+ LE Plus: 컨버세이션 미러 (<-RE)
+ LE Plus: 인텔리젼트 스마트키 (Option 65만)

트림 상향 조정 항목
~ SE->SE Plus: 글로브박스 냉장기능
~ SE->LE Plus: 러기지 스크린
~ SE Plus -> LE: 12V 파워아울렛(트렁크)
~ LE -> LE Plus: 전자식 파킹브레이크
~ LE -> LE Plus : 고급형 콘솔박스
~ LE -> Option: 6CD 체인저... - Bose선택시에 가능
~ LE Plus -> RE: 다기능 센터콘솔 박스


가격표 입니다 - 2009년 4월 변동사항 반영 되어 있습니다.
이때까지의 변동 가격표가 모두 포함 되어 있습니다.

Click! --> 출시부터 현재까지 QM5 가격표 <-- 는 따로 확인 하세요.
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
구글 스프레드시트로 작성 한 것이라 text로 확인 가능 합니다. 복사도 물론 가능!
[지글지글 보기힘든 이미지가 아닙니다]
이전 변경사항도 함께 모두 포함되어 있습니다 (최초 발표 가격/사양 제외)





공식 가격 자료는 아래 자료를 확인 하세요.

2012년 11월 변동 가격표 (종합 가격표)

sm5_price[12].pdf


2012년 7월 변동 가격표 (종합 가격표로, 맨뒷 부분에 위치 함)

qm5_price_201207.pdf


2011년 7월 변동 가격표 [NEW QM5]

qm5_price[7].pdf


2011년 2월 변동 가격표
qm5_price[2].pdf

2010년 7월 변동 가격표 [2011년 형]
201007_2011MY_QM5_price.pdf

2010년 1월 변동 가격표 [2010년 1월 부터 유효]
201001_qm5_price.pdf

2009년 9월 변동 가격표 [2009년 9월 부터 유효]
090901_qm5_price.pdf

2009년 7월 변동 가격표 [2009년 7월 부터 유효]
price_QM5_0907.pdf

2009년 4월 변동 가격표 [2009년 4월 부터 유효]
qm5_price_0904-.pdf

2009년 가격표 입니다. [2009년 1월 부터 유효한 내용입니다 - 6월 까지 개별소비세 인하분 반영]
2009_qm5_price.pdf

아래 파일은 르노삼성자동차 공식 배포 가격 표 입니다. [2008년 10월 부터 유효한 내용 입니다]
2009_QM5_가격표_2008-10-.PDF

아래 두 image 파일은 르노삼성자동차 공식 배포 가격표 입니다. [2008년 9월 까지 유효한 내용 입니다]
그림이므로 원본 크기를 보려면 클릭, 확장 처리 하셔야 합니다.



도움 되셨다면 추천 꾹~ / 감사합니다.




이미 몇주된 이야기 입니다.

요즘 SUV는 디젤엔진의 성능이 매우 좋아서 같은 배기량의 가솔린 차량과 비교하여 두배 정도의 토크를 뿜어 내게 됩니다.
결과적으로 오르막에서 가속 성능이 가솔린 차량과 비교가 되지 않는 다는 것입니다!


2주 전에 청원-상주간 고속도로에서 경험한 내용입니다.


대구에서 수원으로 가기 위한 나름의 최적 경로인 경부-중부내륙-청원상주-경부로 가는 길을 운행중에, 낙동분기점(청원 상주가 고속도로 연결점)에서 2,000cc 대 승용차가 바로 앞에서 나름 스포티 하게 운행을 하고 있는 것입니다.

그 앞에는 대형 트럭이 막아 서 있는 상황이라 진입 구간에서는 트럭-승용차-QM5 이렇게 3대가 쪼르미 가고 있었죠.
이 승용차가 나름 왔다 갔다 끼어들기로 바쁜 척을 하셔서 - 똥꼬 찌르기를 맘에 먹고 있었습니다.

청원상주 구간의 시작은 오르막입니다(상주에서 - 물론 청원에서도 오르막).
이미 이전에 투스카니를 걍 발라버리 경험이 있어서 자신감에 넘치고 있었죠.

자~ 램프를 지나 3차로로 뚫린 시작점이 열렸습니다.

이 승용차 쏘더군요
바로 저도 따라 붙을 각오로 꾸욱! 최대한의 악셀레이팅을 했습니다.
아직 오르막 초반이라 승용차 잘 나가더군요.

그리고, 쭈~욱 밟고 있는 와중에....
아무리 밟고 있어도 앞차와의 거리가 단축되지 않고 조금씩 벌어지고 있는 것입니다. 믿을 수가!
2000cc 차량으로만 생각했기에, 그것도 가솔린 차량이라고 상상 했기에,
나름의 스펙이 좋은(제원상 173마력) QM5 스포티가 따라가지 못하는 것입니다.

앞에서 끼어 드는 차량으로 앞서가던 이 차량이 주춤한 사이, 똥꼬 까지 붙었지만 - 이미 저는 제가 '제낄' 수 있는 상대가 아님을 알아 차렸습니다.

이후로 목표는 그차 뒤라도 계속 따라 가겠다는 것이죠 ㅎㅎ
그리고서는 청원 까지 죽어라 따라만 다녔습니다.

중간에 단 한번 따라 잡았는데, 제가 앞차량으로 인해 간격이 너무 벌어졌는데, 이 앞서 가던 승용차가 궁금 했는지 - 2차로에서 저를 기다리고 있더군요 (ㅠ.ㅠ)

저야 따라가려고 꾹! 풀-악셀 중이었기에 쇙 하고 1차로로 지나 쳤고, 그 순간 2차로로 다시금 조용히 - 진짜 아무일 없었다는 것 처럼 조용히! - 하지만 발은 꾹! 바닥까지 힘을 주고 있었습니다.

곧 뒤처진 이 승용차가 1차로 오르막에서 유유히 2차로에 있던 저를 지나쳐서 스르륵 앞서 갔습니다.
서로 얼굴은 보이지 않지만, 저는 앞만 보고 - 아무렇지 않은듯이 2차로를 굳건히 지키면서, 내리 발고 있는 발에 힘을 빼지 않고서 조용히(?) 앞만보고 간 것이죠.

이후 경부 함류 이후 - 바닥을 향해 가고 있는 연료 게이지를 보면서!
내가 왜 이러고 있을까 생각을 하고, 살아남기 위해(연료!!!) "급 조신 모드(mode)"로 전환을 했습니다.
크루즈 컨트롤로 110km(GPS기준) 로 설정하고 '연비'상태로 바꾸었습니다.

이미 닳아 버리 연료를 아까워 하기에는 너무 늦은 상황이라고 할까요.

앞서 차량의 어떤 차량인지 제대로 파악을 못했는데, 라프(라세티 프리미어) 디젤이 아닐까 생각도 해 보고, VW 차량이 아닐까도 생각을 해 보면서... [뒷 램프가 양쪽으로 동그스름한 2개씩, 퍼지는 빛 형태]
한편으로는 평소보다 속도가 잘 안나오는 것을 연료 문제가 아닐까도 생각을 해 보았습니다.(평소와 다른 주유소 이용)
또한 SUV 특성상 맞바람 상황에서 어쩔 수 없는 한계이지 않을 까도...
맵핑을 해야 할까는 생각 까지!


결과적으로 재미있게 청원/상주간 고속도로를 빠른 속도로 드라이빙 했다는데 의의를 두었습니다.
이렇게 오면 속도도 속도지만, 밤 1시가 넘은 늦은 시간에 지루함을 없앨 수도 있기에 말이죠.


수동기어 인디케이터의 완성

앞서 브레드보드로 만든 회로를 최종적으로 만능기판을 이용하여 구성 했습니다.
향후 확장을 위해 충분한 크기의 기판을 사용 했습니다. 겨우 안쪽에 넣을 크기가 되었더군요 - 좀더 작게 만들 필요가 있어 보입니다.


글은 모두 4개로 구분하여 올렸습니다.




앞쪽 모습입니다. 주문 실수로 저항을 1/2W 용량을 사버렸네요. 굴찍한게 좀 없어 보입니다 ㅎㅎ
중앙 부분에 위치한 풀업 저항 역시 1/2W 용량인데 크기는 1/4W 급과 동일 합니다.




장착 사진을 추가로 소개 드리면 아래와 같습니다.

*실제 최종 완성본에는 뒷쪽에 필터기능용 부품 2개(고전압 필터, 적은 용량 컨덴서 한개)를 추가 했습니다.
오동작 때문에 넣었는데, 필요 없겠더군요. 오동작 원인은 마이컴을 차량 배선에 가까이 붙이지 않으면 됩니다.


세워 둔 곳이 리어덕터 생략된 위치 입니다. 수동모델은 리어덕터가 없기에 공간 확보가 되었네요 @.@


7 Segment 단자를 비교적 길~게 해서 중앙 콘솔까지 연결합니다.


글로브박스를 분리해서 연결하면 매우 쉽습니다. 절대 그냥 하려 하지 마세요 - 분리 할 건 분리 하셔야!




최종 동작 결과 소개를 드립니다.
개별 기어에 맞추어 7-Segment를 통해 현재 기어가 표시가 됨을 확인 할 수 있습니다.
개별 표시는 그냥 바뀌는 것이 아니라 아래의 규칙대로 효과를 보여 줍니다.

기어 변경
해당 기어 숫자가 빠르게 깜빡이면서 눈에 띄도록 표시가 됩니다. 깜빡임에는 몇종류의 형태로 변화 하면서 변화를 보이다가 고정이 됩니다.

기어 변경 조작 중인 경우
기어가 변경중인 경우이고 다음 기어 위치로 고정 되지 않은 상태에서는 점점 희미하게 이전 기어 표시가 어두어 지다가 '-' 표기로 바뀌게 됩니다.

기어 위치 센서에 아무런 값이 입력 되지 않는 경우
이 경우 에러 상태를 알리는 'E'표기가 됩니다.
입력 상태를 확인 할 필요가 있습니다. 특히 센서 동작을 확인 해야 합니다.

후진은 R 표시가 곤란하므로 P. 형태로 표시합니다.
또한 후진 상태에서 일정 시간이 지나면 빠르게 깜빡여서 후진임을 알려줍니다.

중립 상태에서 장시간 대기시에
0으로 표시되던것이 하나의 LED만 점등하면서 회전하는 애니메이션을 보여 줍니다.

다시금 동작 동영상을 소개 드립니다.
시내주행이라 억지로 6단 까지 넣어 봤습니다 ^.^


개별 기어 동작별 표시 변경 내용만 보면 아래와 같습니다.
정차 상태에서 운전석에서 제가 촬영하고, 친구가 조수석에서 조작해서 좀 부드럽지 못합니다.
전체적인 동작을 확인 하는 영상으로 이해 하세요.

*개별 기어 상태에서 변속 동작이 완료 되지 않은 상태로 빠지면 점점 어두워지게 했습니다.
 PWM 동작은 아니고 루프에서 카운트 값을 적당히 조절 했답니다(소스 참조)



개별 기어수에 대한 사진 입니다.














요거이 후진입니다. R 이라 하고 싶었지만 구할 수 있는 표시기가 순수 7 Segment라 P. 으로 표시하고 일정 시간 직후 "깜빡이"게 했습니다.
제가 R에서 실수 해서 한이 맺혀서 말이죠 ㅋㅋㅋ (빵판에서는 부저도 달았었습니다. - 빽빽 거립니다 ㅎㅎ)


이상입니다.
혹시나 수동기어 인디케이터가 필요하신 분께 참고 자료가 되었으면 합니다.



이번 글에는 메인 모듈 회로 구성 회로와 마이컴 모듈인 ATMega128용 소스를 소개 드립니다.

제가 한방에 납땜하고, 설계하고, 코딩하지는 않았습니다.
나름 여러 재료와 함께 브레드보드(일명 빵판)도 생에 처음으로 구입하여 미리 구성하고 확인하여 회로를 완성 했습니다.
전원 연결, 포트 3개를 이용하여 하나는 기어센서로 부터 입력 7개, 디버깅용 - 즉 센서 감지용 LED 7개(실은 미리 8개 연결), 그리고 최종 기어단수 표시용 7-segment용 출력 8단자 입니다.

[수정: 2010-1-8 ]
풀업 저항 10k옴* 8개는 삭제 합니다. 소스코드도 수정 되었습니다.
제가 내부 풀업 셋팅을 몰라서 사용 했는데, 코드 한줄 추가로 설정 했습니다(초자라 이해를...)
파일도 수정된 내용으로 바꾸었습니다.
아래 회로 그림에서 10k부분은 완전히 제거 하시면 됩니다(더 간단하죠)


글은 모두 4개로 구분하여 올렸습니다.
1. 소개글, 개별 단수 인식 방법과 필요한 부품
2. 센서 모듈 만들기와 장착
3. 회로 구성을 위한 회로도와 마이컴 소스코드 [지금 보고있는 글입니다]
4. 완성품 설치와 동작 모습 소개


우선 브레드 보드로 마이컴 모듈을 장착하고, 기어 상태 입력을 위한 부분, 현재 입력 상태 확인용 LED 부분, 최종 기어 단수 표시를 위한 7-Segment 출력 부분으로 구성 했습니다.

입력은 Port A 단자와 연결
입력값 확인용 출력단은 Port C 단자와 연결
7-Segment 출력은 Port  F 단자와 연결 했습니다.

포트 선택의 기준은 한쪽에 몰려 있어서 그냥 사용 했습니다.
AVR은 처음 만져 보는 것이라, 인터럽터, 타이머쪽 고려는 전혀 되지 않았습니다.
- 회로, 코드 보시고 고수분들의 한수 지도 의견 환영 합니다.

상세 연결은 브레드 보드와 연결된 실제 회로 구성 사진으로 대신 하고자 합니다.

위 사진 보고는 느낌밖에 오지 않습니다 ^.^ 밑에 회로도를 보시기 바랍니다.

중요한 핀 번호와 개별 연결 단자와의 구성은 아래와 같이 정리 할 수 있습니다.


네... 회로도가 잘 되었는지 모르겠네요 ^.^


AVR 동작을 위한 code는 아래와 같습니다. 실제 사용하는 code입니다.
제가 AVR 프로그래밍은 처음이라 인터럽트, 타이머는 사용하지 않는 단순한 폴링 방식의 구현임을 감안 하셨으면 합니다. 고수분들의 한수 지도 환영 합니다.
코드에 코멘트를 보시면 이해에 도움이 될 듯 합니다.

다운로드:

/*******************************************************************************
 (C) 2009 Seung-Won Lee   http://whoisit.tistory.com    SoftWareYi@gmail.com


  수동기어 단수표시 장치

  @File  GearPositionIndicator.c
*******************************************************************************/


#include <avr/io.h>

#define    PORT_SEG            PORTF    // Segment 출력용 port
#define    SEG_COMMON_ANODE    1        // Anode 공통 == + 극 공통으로 출력이 0으로 나가야 동작 하는 경우

#ifdef    SEG_COMMON_ANODE
    #define    SEGOUT(value)    (~value)    // Coommon Anode이므로 bit 상태를 뒤집는다
#else
    #define    SEGOUT(value)    (value)
#endif


const unsigned char    SEGMENT_MINUS    = 0b10000000;    // -
const unsigned char    SEGMENT_0        = 0b01110111;    // 0
const unsigned char    SEGMENT_1        = 0b00010100;    // 1
const unsigned char    SEGMENT_2        = 0b10110011;    // 2
const unsigned char    SEGMENT_3        = 0b10110110;    // 3
const unsigned char    SEGMENT_4        = 0b11010100;    // 4
const unsigned char    SEGMENT_5        = 0b11100110;    // 5
const unsigned char    SEGMENT_6        = 0b11100111;    // 6
const unsigned char    SEGMENT_7        = 0b01110100;    // 7
const unsigned char    SEGMENT_8        = 0b11110111;    // 8
const unsigned char    SEGMENT_9        = 0b11110110;    // 9
const unsigned char    SEGMENT_BACK    = 0b11111001;    // P. for Back
const unsigned char    SEGMENT_ERROR    = 0b11101011;    // E. for Error
const unsigned char    SEGMENT_H3        = 0b10100010;    // 한자 3
const unsigned char    SEGMENT_ALL        = 0b11111111;    // All for test


//******************************************************************************
//******************************************************************************
void init( void )
{
    // Enable pull up
    int    SpecialFunctionIO = SFIOR;
    SpecialFunctionIO = ~4 & SpecialFunctionIO;
    SFIOR = SpecialFunctionIO;
}



//******************************************************************************
// 7Segement test 출력
//******************************************************************************
void Display7SegmentOnPortF( void )
{
    const unsigned char    segmentData[] = {
                SEGMENT_0,        // 0
                SEGMENT_1,        // 1
                SEGMENT_2,        // 2
                SEGMENT_3,        // 3
                SEGMENT_4,        // 4
                SEGMENT_5,        // 5
                SEGMENT_6,        // 6
                SEGMENT_7,        // 7
                SEGMENT_8,        // 8
                SEGMENT_9,        // 9
                SEGMENT_H3,        // =
                SEGMENT_BACK,    // R
                SEGMENT_ALL,    // All for test
    };
    static int    index = 0;
    static long int delay = 0;

    if ( ++delay > 10000 )
    {
        delay = 0;
        PORT_SEG = SEGOUT(segmentData[ index++ ]);    // Invert for common Anode LED
        if ( index >= sizeof(segmentData)/sizeof(segmentData[0]) )
            index = 0;
    }
    else
    {
        //PORT_SEG = SEGOUT(0);    // Turn off
    }
}

//******************************************************************************
// Port로 부터 입력된 기어 위치값으로 부터 현재 기어 위치를 char 문자로 돌려준다
//    중립='N'
//    각 단수='1'~'6'
//    후진:'B'
//    기어조작중:'-'
//    에러상태:'E'
//******************************************************************************
typedef struct
{
    char    state;
    char    position;
} stateToPosition;

char getTransmissionValue( char state )
{
    const stateToPosition    stateData[] = {
        { 0b00100010, 'N' },    // Natural
        { 0b00010100, '1' },    // 1
        { 0b01000100, '2' },    // 2
        { 0b00010010, '3' },    // 3
        { 0b01000010, '4' },    // 4
        { 0b00010001, '5' },    // 5
        { 0b01000001, '6' },    // 6
        { 0b00011000, 'B' },    // Back
    };
    char    result = '-';
    int        sensingCount = 0;
    int        i;

    state = state & 0b01111111;    // 상위 1bit 사용 안함 처리
   
    // CheckError - 최소한 하나의 bit는 1이어야 정상이다. (실은 2개)
    if ( !(0b01111111 & state) )
    {
        return 'E';    // 센서로부터 아무런 입력값이 없을 경우 Error처리
    }

    // 변속 중인 상태 확인 -> 앞뒤
    sensingCount += ( state & 0b01000000 ) ? 1 : 0;
    sensingCount += ( state & 0b00100000 ) ? 1 : 0;
    sensingCount += ( state & 0b00010000 ) ? 1 : 0;
    if ( sensingCount > 1 )    // 두 위치값이 동시에 입력되면 변동 중인 경우
        return result;

    // 변속 중인 상태 확인 -> 좌우
    sensingCount = 0;
    sensingCount += ( state & 0b00001000 ) ? 1 : 0;
    sensingCount += ( state & 0b00000100 ) ? 1 : 0;
    sensingCount += ( state & 0b00000010 ) ? 1 : 0;
    sensingCount += ( state & 0b00000001 ) ? 1 : 0;
    if ( sensingCount > 1 )    // 두 위치값이 동시에 입력되면 변동 중인 경우
        return result;

    // 모두 통과 되었다면 단수 확인 과정, 확인 불가시 '-' 처리가 default
    for ( i=0; i<sizeof(stateData)/sizeof(stateData[0]); i++ )
    {
        if ( stateData[i].state == state )
        {
            result = stateData[i].position;
            break;
        }
    }

    return result;
}

//******************************************************************************
// getTransmissionValue로 부터 받아진 결과값을 입력하면 포트출력 값을 돌려준다
//******************************************************************************
typedef struct
{
    char    mode;
    char    segmentData;
} modeToSegment;

char getSegmentData( char currentMode )
{
    const modeToSegment    modeToSegmentData[] = {
        { '-', SEGMENT_MINUS },    // -
        { 'N', SEGMENT_0 },    // 0
        { '1', SEGMENT_1 },    // 1
        { '2', SEGMENT_2 },    // 2
        { '3', SEGMENT_3 },    // 3
        { '4', SEGMENT_4 },    // 4
        { '5', SEGMENT_5 },    // 5
        { '6', SEGMENT_6 },    // 6
        { 'B', SEGMENT_BACK },    // R == P.
        { 'E', SEGMENT_ERROR },    // E.
    };
    int        i;
    char    segmentData = SEGMENT_ERROR;    // Default to Error


    // 입력값에 대응하는 Segment값을 가져온다
    for ( i=0; i<sizeof(modeToSegmentData)/sizeof(modeToSegmentData[0]); i++ )
    {
        if ( modeToSegmentData[i].mode == currentMode )
        {
            segmentData = modeToSegmentData[i].segmentData;
            break;
        }
    }

    return segmentData;
}

/*******************************************************************************
 segmentData를 포트를 이용하여 출력한다
 이어 위치가 변경될 경우 깜빡이는 효과를 시차를 이용하여 보여준다
 중립(0)상태가 일정시간 지속될 경우 animation 효과(뱅글뱅글)를 보여준다

 변속 조작 진행 상태('-')의 경우 이전 단수가 서서이 사라지는 형태로 처리한다.
*******************************************************************************/
void displaySegmentData( char segmentData )
{
    const char segmentAnimationData[] = {        // 왼쪽으로 회전하는 에니메이션
        0b00000001,
        0b00000010,
        0b00000100,
        0b00010000,
        0b00100000,
        0b01000000,
    };
    static char prevData = 0;
    static unsigned long int    timingCount = 0;
    static unsigned int            rotateTimingCount = 0;
    static char dimmingMode = 0;


    // 특정 단수 --> '-' 즉 기어 조작 진행 중인 경우
    // '-' 표시 전에 이전 단수를 희미하게 사라지게 한다
    if ( ( prevData != segmentData ) && ( SEGMENT_MINUS == segmentData ) )
    {
        if ( !dimmingMode )
        {
            dimmingMode = 1;    // Dimming mode전환
            timingCount = 0;
            PORTB = 0;            // Clear
        }

        if ( timingCount < 1000 )        // 조작 직후 이전 기어 위치 유지
            PORT_SEG = SEGOUT( prevData );
        else
        if ( timingCount < 3000 )
            PORT_SEG = ( 90 < timingCount % 100 ) ? SEGOUT(0) : SEGOUT(prevData);
        else
        if ( timingCount < 5000 )
            PORT_SEG = ( 70 < timingCount % 100 ) ? SEGOUT(0) : SEGOUT(prevData);
        else
        if ( timingCount < 7000 )
            PORT_SEG = ( 50 < timingCount % 100 ) ? SEGOUT(0) : SEGOUT(prevData);
        else
        if ( timingCount < 9000 )
            PORT_SEG = ( 30 < timingCount % 100 ) ? SEGOUT(0) : SEGOUT(prevData);
        else
        if ( timingCount < 11000 )
            PORT_SEG = ( 10 < timingCount % 100 ) ? SEGOUT(0) : SEGOUT(prevData);
        else
        if ( timingCount < 13000 )
            PORT_SEG = ( 5 < timingCount % 100 ) ? SEGOUT(0) : SEGOUT(prevData);
        else
        {
            PORT_SEG = (char)SEGOUT(SEGMENT_MINUS);    // '-' 최종 반영
            prevData = segmentData;    // '-'로 이전값 설정
            dimmingMode = 0;        // timingCount reset용
        }
       
        // 효과 과정 까지 timingCount 증가
        ++timingCount;
        return;
    }
    else
    {    // Dimming 도중에 다른 기어로 진입시에 reset 처리하여 차후 기어 조작 진행 상태 반영
        if ( dimmingMode )
        {
            dimmingMode = 0;
            timingCount = 0;
        }
    }


    // 일반적인 변동 상황
    if ( prevData != segmentData )
    {
        PORT_SEG = SEGOUT(segmentData);    // Invert for common Anode LED
        prevData = segmentData;
        timingCount = 0;        // For effect
        rotateTimingCount = 0;
    }
    else
    {
        if ( timingCount < 1000 )
            PORT_SEG = ( 100 < timingCount % 200 ) ? SEGOUT(prevData) : SEGOUT(0);
        else if ( timingCount < 3000 )
            PORT_SEG = ( 200 < timingCount % 500 ) ? SEGOUT(0) : SEGOUT(prevData);
        else if ( timingCount < 6000 )
            PORT_SEG = ( 300 < timingCount % 1000 ) ? SEGOUT(0) : SEGOUT(prevData);
        else if ( timingCount < 10000 )
            PORT_SEG = SEGOUT(prevData);
       
        // 효과 과정 까지 timingCount 증가
        if ( timingCount < 600000 )
        {
            ++timingCount;
            if ( (timingCount > 50000) && (SEGMENT_BACK == prevData) )
            {
                //PORT_SEG = ( 4000 < timingCount % 6000 ) ?  ~0 : ~prevData;
                if ( 4000 < timingCount % 6000 )
                {
                    PORT_SEG = SEGOUT(0);
                    PORTB = 0xFF;
                }
                else
                {
                    PORT_SEG = SEGOUT(prevData);
                    PORTB = 0;               
                }
            }
        }
        // 효과 완료 시점
        else
        {
            if ( SEGMENT_0 == prevData )
            {
                static int segmentIndex = 0;

                // 0 인 경우 뱅글뱅글 돌아가는 animation 출력 시작
                if ( ++rotateTimingCount > 20000 )
                {
                    PORT_SEG = SEGOUT(segmentAnimationData[segmentIndex]);
               
                    if ( ++segmentIndex >= sizeof(segmentAnimationData)/sizeof(segmentAnimationData[0]) )
                        segmentIndex = 0;
                    rotateTimingCount = 0;
                }
            }

        }

    }
   
}

//******************************************************************************
//******************************************************************************
int    main( void )
{
    const unsigned int    inOutTime = 1000;
    unsigned long int    timingCount = 0;
    char    currentMode = 'N';
    char     segmentData = 0;

    init();

    DDRA = 0x00;
    DDRC = 0xFF;
    DDRF = 0xFF;
    DDRB = 0xFF;

    PORTA = 0xFF;        // Input port에 1을 setting하여 Internal pull-up 저항을 활성화
    PORTC = 0x00;

    PORT_SEG = 0xFF;        // Common anode 이므로 1상태가 off 가 된다
    PORTB = 0x00;        // 버즈 출력 시도

    while ( 1 )
    {
        char input = 0;

        if ( 0 == timingCount % inOutTime*10 )
        {
            input = ~PINA;    // N==1 접속==0
            PORTC = input;

            // 상태값으로 부터 기어 단수 위치를 판단한다.
            currentMode = getTransmissionValue( input );
            segmentData = getSegmentData( currentMode );
        }

        displaySegmentData( segmentData );
       




        if ( ++timingCount >= 60000 )
            timingCount = 0;
    }


}

다음글은 최종 완성품 사진과 실제 동작사진, 나머지 동영상 모음을 올려 드리도록 하겠습니다.

+ Recent posts