질문게시판 > 답변 : 사진과 구동 영상으로 다시 질문하겠습니다!

인기검색어 > 아두이노 센서 ATMEGA128

최신글 질문게시판 동영상강좌 가입하기

▼ BASIC4MCU 후원업체 신제품 정보 ▼

▲ BASIC4MCU 후원업체 신제품 정보 ▲

BASIC4MCU > 질문게시판

답변 : 사진과 구동 영상으로 다시 질문하겠습니다!

페이지 정보

작성자 master 작성일19-12-27 22:00 조회6,745회 댓글2건

본문

​​밑줄 친 부분은 제가 LCD 안정화 코드를 따온 것입니다. ​​신경 안쓰셔도 됩니다. 적

어둔 코드는 화재 감지기를 한 번 구현해본 것인데 가변 저항을 돌려 4.0V 이상 일 때 화재로 판단하여 LED 점등(PA7 단자) 및 스피커 알람, LCD에 fire 점등이며 평상시에는 전압만 출력합니다. 구동이 잘됩니다.
#include        
#include
 

 

#define LINE2    0xC0    // 2nd Line Move
#define HOME    0x02    // Cursor Home
#define RSHIFT    0x1C    // Display Right Shift
#define LSHIFT    0x18    // Display Left Shift
#define DISPON    0x0c     // Display On                      
#define DISPOFF    0x08    // Display Off

void LCD_init(void);
void LCD_String(char flash *str);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
void adc_display(void);

int adc_value = 0;
float Vref = 5.0, Vwarn = 4.0, Vdetect = 0;
int cnt_bell = 0;

void main(void)

    ADMUX = 0x00;
    ADCSRA = 0x87;
   
    ETIMSK = 0x04;
    TCCR3A = 0x00;
    TCCR3B = 0x04;
    TCNT3H = 0x85;
    TCNT3L = 0xED;
   
    DDRB = 0x30;
    DDRA = 0x80;
    PORTA = 0xff;
   
    SREG = 0x80;
   
    LCD_init();
    adc_display();
          
    while(1){ 
        ADCSRA = 0xc7;
        while((ADCSRA & 0x10) == 0);
        adc_value0 = (int)ADCL + ((int)ADCH << 8);
        Vdetect = (float)adc_value * Vref / 1024;  
    }             
}  
interrupt [TIM3_OVF] void timer_tin0 (void)
{
    TCNT3H = 0x85;
    TCNT3L = 0xED;
   
    if(Vdetect >= Vwarn){
        TCCR1A = 0x40;
        TCCR1B = 0x0a;
       
        if(cnt_bell == 0){
            PORTA = 0x00;
            OCR1A = 2082;
            Command(CLEAR);
            LCD_String("fire!!!");
            cnt_bell = 1;
            }
            else{
                PORTA = 0xff;
                OCR1A = 2777;
                Command(CLEAR);
                cnt_bell = 0;
            }
    }
    else{
        TCCR1A = 0x00;
        TCCR1B = 0x0a;
        PORTA = 0xff;
        adc_display();
    }
}  
void adc_display(void)
{
    int temp0 = 0, temp1 = 0, temp = 0;
   
    Command(CLEAR);
    LCD_String("Value:");

    temp = (int)(Vdetect * 10 + 0.5);
   
    temp1 = temp / 10;
    temp0 = temp % 10;
   
    Data(0x30 + temp1);
    LCD_String(".");
    Data(0x30 + temp0);
    LCD_String("V");
}   
// LCD 초기화 함수
void LCD_init(void)
{                         
    DDRC = 0xFF;    // 포트 C 출력 설정
    PORTC &= 0xFB;    //E = 0;
   
    // 충분한 지연시간을 통한 안정화 과정
     delay_ms(15);
    Command(0x20);    // D5=1
    delay_ms(5);
    Command(0x20);    // D5=1
    delay_us(100);
    Command(0x20);    // D5=1

    // 초기화 과정
    Command(0x28);    // function set
    Command(0x06);    // entry mode set
    Command(0x01);    // all clear
    Command(0x0c);    // display on
}

// 인스트럭션 쓰기 함수
void Command(unsigned char byte)
{
   Busy();

   // 인스트럭션 상위 바이트
   PORTC = (byte & 0xF0);   // 데이터  
   PORTC &= 0xFE;   // RS = 0;          
   PORTC &= 0xFD;   // RW = 0; 
   delay_us(1);    
   PORTC |= 0x04;   // E = 1;
   delay_us(1);
   PORTC &= 0xFB;   // E = 0;

   // 인스트럭션 하위 바이트
   PORTC = ((byte<<4) & 0xF0);   // 데이터
   PORTC &= 0xFE;   // RS = 0;
   PORTC &= 0xFD;   // RW = 0;
   delay_us(1);       
   PORTC |= 0x04;   // E = 1;
   delay_us(1);
   PORTC &= 0xFB;   // E = 0;
}

// 문자열 출력 함수
void LCD_String(char flash *str)
{                         
   char flash *pStr=0;

   pStr = str;  
   while(*pStr) Data(*pStr++);
}

// char flash : pointer declaration for program memory
// char eeprom : pointer declaration for EEPROM

//데이터 쓰기 함수
void Data(unsigned char byte)
{
   Busy();
       
   // 데이터 상위 바이트
   PORTC = (byte & 0xF0);   // 데이터
   PORTC |= 0x01;   //RS = 1;
   PORTC &= 0xFD;   //W = 0;
   delay_us(1);       
   PORTC |= 0x04;   //E = 1;
   delay_us(1);
   PORTC &= 0xFB;   //E = 0;

   // 데이터 하위 바이트
   PORTC = ((byte<<4) & 0xF0);     // 데이터
   PORTC |= 0x01;   //RS = 1;
   PORTC &= 0xFD;   //RW = 0;    
   delay_us(1);       
   PORTC |= 0x04;   //E = 1;
   delay_us(1);
   PORTC &= 0xFB;   //E = 0;
}

// Busy Flag Check -> 일반적인 BF를 체크하는 것이 아니라
// 일정한 시간 지연을 이용한다.
void Busy(void)
{
   delay_ms(2);
}

 


​위 코드와

 

#include        
#include

#define LINE2    0xC0    // 2nd Line Move
#define HOME    0x02    // Cursor Home
#define RSHIFT    0x1C    // Display Right Shift
#define LSHIFT    0x18    // Display Left Shift
#define DISPON    0x0c     // Display On                      
#define DISPOFF    0x08    // Display Off

void LCD_init(void);
void LCD_String(char flash *str);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
void degree_display(void);
void v_value(void);

int rot_base=375, rot_min=275, rot_max=475;
int rot_delta1=1, rot_delta2=4, rot_delta=0;
int rot_value=0, rot_dir=2;
int adc_value=0;
float Vref=5.0, f_val=0;
int temp10=0;

void main(void)
{
    DDRB=0xff;
    DDRF=0xff;
   
    ADMUX=0x00;   
    ADCSRA=0b10000111;
   
    ETIMSK=0b00000100;
    TCCR3A=0x00;
    TCCR3B=0b00000100;
    TCNT3H=0xE7;
    TCNT3L=0x96;
   
    TCCR1A=0b10000010;
    TCCR1B=0b00011011;
    ICR1H=0x09;
    ICR1L=0xc3;

    SREG=0b10000000;
   
    rot_value=rot_base;
    OCR1A=rot_value;

    LCD_init();
    degree_display();
   
      while(1)
    {
        v_value();
        
        if(temp10>0&&temp10<=15)
        {
            rot_dir=1;
            rot_delta=rot_delta2;
        }
        else if(temp10>15&&temp10<=20)
        {
            rot_dir=1;
            rot_delta=rot_delta1;
        }
        else if(temp10>30&&temp10<=35)
        {
            rot_dir=0;
            rot_delta=rot_delta1;
        }
        else if(temp10>35&&temp10<=50)
        {
            rot_dir=0;
            rot_delta=rot_delta2;
        }
        else
        {  
            rot_dir=2;
            OCR1A=rot_value;  
        }
       
    }
 
}

interrupt [TIM3_OVF] void timer_int3(void)
{
    TCNT3H=0xE7;
    TCNT3L=0x96;
       
    if(rot_dir==0)
    {
        if(rot_value<=rot_max)
        {
            rot_value+=rot_delta;
        }
        else
        {
            rot_value=rot_max;
        }
        OCR1A=rot_value;
    }
 
    else if(rot_dir==1)                                                                                                                   
    {
        if(rot_value>=rot_min)
        {
            rot_value-=rot_delta;
        }
        else
        {
            rot_value=rot_min;
        }
        OCR1A=rot_value;
    } 
       
    degree_display();       
}
void v_value(void)
{
    ADCSRA=0b11000111;
    while((ADCSRA&0x10)==0);
    adc_value=(int)ADCL+((int)ADCH<<8);
   
    f_val=(float)adc_value*Vref/1024;
    temp10=(int)(f_val*10+0.5);   
}

void degree_display(void)
{
    float degree_value=0;
    int temp0=0, temp1=0, temp2=0, temp=0;
    int v1=0, v2=0;
                        
    Command(HOME);
    LCD_String("Degree : ");
   
    if(rot_value>=rot_base)
    {                  
        degree_value=(float)(rot_value-rot_base)*80/200;
        LCD_String("+");  
    }
    else
    {
        degree_value=(float)(rot_base-rot_value)*80/200;
        LCD_String("-");
    }
   
    temp=(int)(degree_value*10);
   
    temp2=temp/100;
    temp=temp%100;
    temp1=temp/10;
    temp0=temp%10;
   
    Data(0x30+temp2);
    Data(0x30+temp1);
    LCD_String(".");
    Data(0x30+temp0);
   
    Command(LINE2);
    LCD_String("Value : ");
   
    v1=temp10/10;
    v2=temp10%10;
   
    Data(0x30+v1);
    LCD_String(".");
    Data(0x30+v2);
    LCD_String("V");
}
// LCD 초기화 함수
void LCD_init(void)
{                         
   DDRC = 0xFF;   // 포트 C 출력 설정
   PORTC &= 0xFB;   //E = 0;
  
   // 충분한 지연시간을 통한 안정화 과정
    delay_ms(15);
   Command(0x20);   // D5=1
   delay_ms(5);
   Command(0x20);   // D5=1
   delay_us(100);
   Command(0x20);   // D5=1

   // 초기화 과정
   Command(0x28);   // function set
   Command(0x06);   // entry mode set
   Command(0x01);   // all clear
   Command(0x0c);   // display on
}
// 인스트럭션 쓰기 함수
void Command(unsigned char byte)
{
   Busy();

   // 인스트럭션 상위 바이트
   PORTC = (byte & 0xF0);   // 데이터  
   PORTC &= 0xFE;   // RS = 0;          
   PORTC &= 0xFD;   // RW = 0; 
   delay_us(1);    
   PORTC |= 0x04;   // E = 1;
   delay_us(1);
   PORTC &= 0xFB;   // E = 0;

   // 인스트럭션 하위 바이트
   PORTC = ((byte<<4) & 0xF0);   // 데이터
   PORTC &= 0xFE;   // RS = 0;
   PORTC &= 0xFD;   // RW = 0;
   delay_us(1);       
   PORTC |= 0x04;   // E = 1;
   delay_us(1);
   PORTC &= 0xFB;   // E = 0;
}

// 문자열 출력 함수
void LCD_String(char flash *str)
{                         
   char flash *pStr=0;

   pStr = str;  
   while(*pStr) Data(*pStr++);
}

// char flash : pointer declaration for program memory
// char eeprom : pointer declaration for EEPROM

//데이터 쓰기 함수
void Data(unsigned char byte)
{
   Busy();
       
   // 데이터 상위 바이트
   PORTC = (byte & 0xF0);   // 데이터
   PORTC |= 0x01;   //RS = 1;
   PORTC &= 0xFD;   //W = 0;
   delay_us(1);       
   PORTC |= 0x04;   //E = 1;
   delay_us(1);
   PORTC &= 0xFB;   //E = 0;

   // 데이터 하위 바이트
   PORTC = ((byte<<4) & 0xF0);     // 데이터
   PORTC |= 0x01;   //RS = 1;
   PORTC &= 0xFD;   //RW = 0;    
   delay_us(1);       
   PORTC |= 0x04;   //E = 1;
   delay_us(1);
   PORTC &= 0xFB;   //E = 0;
}

// Busy Flag Check -> 일반적인 BF를 체크하는 것이 아니라
// 일정한 시간 지연을 이용한다.
void Busy(void)
{
   delay_ms(2);
}

 

위 코드는

 

RC 서보 모터를 시작할 때 0도로 설정하고

 

 가변저항의 값을

 

3V - 3.5V 구간으로 조정하면, CW 방향으로 100msec 단위로 0.4도씩 증가

 

3.5V - 5V 구간으로 조정하면, CW 방향으로 100msec 단위로 1.6도씩 증가

 

2V -1.5V 구간으로 조정하면, CCW 방향으로 100msec 단위로 0.4도씩 증가

 

1.5V - 0V 구간으로 조정하면, CCW 방향으로 100msec 단위로 1.6도씩 증가

 

2-3V 구간으로 조정하면, 모터 현재 각도를 유지하고 현재 각도를 LCD에 출력하게 끔 코딩했습니다. 잘 돌아갑니다.

 

제가 하고 싶은것은 위 코드 2개를 이용하여 0 - 1.5V까지는 서보모터가 약하게 돌며

                                                                      1.5V - 3V까지는 중간으로 돌며

                                                                      3V - 4V가 되면 빠르게 돌면서

                                                                      4V에 도달 시  화재로 판단하여 LED 점등(PA7 단자) 및 스피커 알람, LCD에 fire 점등을 하고 싶습니다.

 

제가 궁금한 것은 이것입니다.

1. 가변저항 하나는 전압을 변화시키는 것이고 하나는 민감도를 조절하기 위해 만들었는데 잘 되질 않습니다.

2. 제가 구현하고 싶은 것은 단지 화재 경보기가 아니라 화재 발생 강도에 따라 바람(모터)의 세기도 바뀌게 만들고 싶어서 일단 따로 따로 구현은 해놨는데 저걸 이제

0 - 1.5V까지는 서보모터가 약하게 돌며 

1.5V - 3V까지는 중간으로 돌며

3V - 4V가 되면 빠르게 돌면서

4V에 도달 시  화재로 판단하여 LED 점등(PA7 단자) 및 스피커 알람, LCD에 fire 점등을 코딩하는 것에서 어려움을 겪고 있습니다. 취합을 하려면 어떻게 해야할 지 도움을 얻고 싶습니다.
 

//

<답변내용>------------------------------------------------------

 

  DDRF=0xff;

입력핀을 출력으로 설정하면 고장납니다.
입출력 설정을 제대로 하지 않아서 값을 읽지 못했으니
위 코드를 삭제하고 다시 돌려보세요

//

 

// MCU BASIC: https://www.basic4mcu.com
// DateTime : 2019-12-27 오후 9:59:14
// by Ok-Hyun Park
//
#include <mega128.h>
#include <delay.h>
#include <stdio.h>
//
#define LINE2    0xC0 // 2nd Line Move
#define HOME     0x02 // Cursor Home
#define RSHIFT   0x1C // Display Right Shift
#define LSHIFT   0x18 // Display Left Shift
#define DISPON   0x0c // Display On
#define DISPOFF  0x08 // Display Off
//
char  str[30];
int   adc_value=0,cnt_bell=0;
float Volt10=0;
//
void adc_display(void){
  sprintf(str,"Value: %d.%d[V]",Volt10/10,Volt10%10);
  Command(LINE2); LCD_String(str);
}
//
interrupt[TIM3_OVF]void timer_tin0(void){ // 500ms
  TCNT3H=0x85TCNT3L=0xED;
  if(Volt10>=40){ // Vwarn=4.0V
    TCCR1A=0x40TCCR1B=0x0a;
    if(cnt_bell==0){ cnt_bell=1PORTA=0x00OCR1A=2082Command(HOME); LCD_String("fire!!!"); }
    else           { cnt_bell=0PORTA=0xffOCR1A=2777Command(HOME); LCD_String("       "); }
  }
  elseTCCR1A=0x00TCCR1B=0x0aPORTA=0xffadc_display(); }
}
//
void main(void){
  DDRB=0x30DDRA=0x80PORTA=0xff;
  LCD_init();
  ADCSRA=0x87adc_display();
  TCCR3B=0x04TCNT3H=0x85TCNT3L=0xEDETIMSK=0x04// 500ms
  SREG=0x80;
  while(1){
    ADCSRA=0xC7while(!(ADCSRA&0x10)); ADCSRA|=0x10;
    adc_value0=ADCW;
    Volt10=(int)((float)adc_value*5.0/1023.0+0.5);
  }
}
//---------------------------------------------위 코드와
#include <mega128.h>
#include <delay.h>
#include <stdio.h>
//
#define LINE2    0xC0 // 2nd Line Move
#define HOME     0x02 // Cursor Home
#define RSHIFT   0x1C // Display Right Shift
#define LSHIFT   0x18 // Display Left Shift
#define DISPON   0x0c // Display On
#define DISPOFF  0x08 // Display Off
//
char  str[30];
int   rot_base=375,rot_min=275,rot_max=475;
int   rot_delta1=1,rot_delta2=4,rot_delta=0;
int   rot_value=0,rot_dir=2;
int   adc_value=0,Volt10=0;
//
void v_value(void){
  ADCSRA=0xC7while(!(ADCSRA&0x10)); ADCSRA|=0x10;
  adc_value=ADCW;
  Volt10=(int)((float)adc_value*50./1023.0+0.5);
}
//
void degree_display(void){
  int   degree;
  //
  degree=(rot_value-rot_base)*4;
  sprintf(str,"Degree: %05d",degree);
  Command(HOME); LCD_String(str);
  //
  sprintf(str,"Value: %d.%d[V]",Volt10/10,Volt10%10);
  Command(LINE2); LCD_String(str);
}
//
interrupt[TIM3_OVF]void timer_int3(void){ // 500ms
  TCNT3H=0xE7TCNT3L=0x96;
  if(rot_dir==0){
    if(rot_value<=rot_max){ rot_value+=rot_delta; }
    else                  { rot_value =rot_max;   }
    OCR1A=rot_value;
  }
  else if(rot_dir==1){
    if(rot_value>=rot_min){ rot_value-=rot_delta; }
    else                  { rot_value =rot_min;   }
    OCR1A=rot_value;
  }
  degree_display();
}
//
void main(void){
  DDRB=0xff;
  LCD_init(); degree_display();
  rot_value=rot_base;
  TCCR1A=0x82TCCR1B=0x1BICR1=0x09c3OCR1A=rot_value;
  TCCR3B=0x04TCNT3H=0xE7TCNT3L=0x96ETIMSK=0x04// 500ms
  ADCSRA=0x87;
  SREG=0x80;
  while(1){
    v_value();
    if     (Volt10<=15){ rot_dir=1rot_delta=rot_delta2; }
    else if(Volt10<=20){ rot_dir=1rot_delta=rot_delta1; }
    else if(Volt10<=30){ rot_dir=2OCR1A=rot_value;      } // 센터
    else if(Volt10<=35){ rot_dir=0rot_delta=rot_delta1; }
    else               { rot_dir=0rot_delta=rot_delta2; }
  }
}

LCD 코드는 문제없다고 하니 생략했습니다.

 

LCD 코드를 위로 올리고

인터럽트 함수를 아래에

메인을 제일 아래에 작성하면

함수 프로토타입을 생략가능한 것이 늘어납니다.

소스코드가 간단해지죠

 

LCD 출력을 sprintf를 사용해서 작성 했습니다.

  • BASIC4MCU 작성글 SNS에 공유하기
  • 페이스북으로 보내기
  • 트위터로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

댓글 : 2

조회수 : 6,745

Busan님의 댓글

Busan 작성일

master님 답변 정말 감사드립니다. 그런데 제가 main 문을 2개를 써본 적이 없어서 잘 모르겠는데 저 코드를 그대로 쓰면
0 - 1.5V까지는 서보모터가 약하게 돌며

1.5V - 3V까지는 중간으로 돌며

3V - 4V가 되면 빠르게 돌면서

4V에 도달 시  화재로 판단하여 LED 점등(PA7 단자) 및 스피커 알람, LCD에 fire 점등이 되는 것인가요??

main문과 선언이 중복되요 오류가 발생하진 않나요??

두 코드를 취합해서 쓰고 싶은데 main문이 중복이되서요 ㅠㅠ

두 코드를 하나처럼 쓰고 싶은데 어떻게 구성해야할 지 몰라서 댓글 남깁니다.

master님의 댓글

master 댓글의 댓글작성일

소스코드를 합치지 않은 상태입니다.
심각한 오류를 체크 해드렸으니
각각 동작시켜서 제대로 동작하는지 확인하고
합쳐서 만들어보세요

게시물 검색

BASIC4MCU > 질문게시판 목록

제목 날짜
공지 MCU, AVR, 아두이노 등 전자공학에 관련된 질문은… 스태프  19-01-15
공지 사이트 이용 안내 댓글[25] master  17-10-29
질문 라즈베리파이4 신형 선택문제 댓글[1] maximum 새글 22-06-26
질문 음전압 ADC 댓글[1] 412904 새글 22-06-26
질문 아두이노 센서값 출력 질문입니다! 댓글[1] 아궁2  22-06-24
질문 ATmega128, ATmega28 RS232통신 첨부파일Moon4201  22-06-24
답변 답변 : ATmega128, ATmega28 RS232… 댓글[1] master  22-06-25
질문 서보모터, 온습도센서 코드 질문 댓글[2] 첨부파일kshdlfaldfh  22-06-22
답변 답변 : 서보모터, 온습도센서 코드 질문 댓글[15] master  22-06-22
질문 steppermulti5 질문 응애  22-06-21
답변 답변 : steppermulti5 질문 댓글[1] master  22-06-22
질문 atmega128 avr usart 질문 snoflak  22-06-21
답변 답변 : atmega128 avr usart 질문 댓글[5] master  22-06-21
질문 사용자 정의 함수 변환 하는 방법 댓글[2] 첨부파일da0800  22-06-21
질문 atmega128 댓글[1] 양의노래  22-06-20
질문 아두이노 동시동작 재질문 댓글[9] 첨부파일죠르디  22-06-20
질문 초음파센서로 dc모터 제어하기 댓글[1] 첨부파일난쟁2  22-06-20
질문 아두이노 동시동작 댓글[7] 죠르디  22-06-19
질문 ATMEGA128 UART,FND 연동 질문 JMOD  22-06-19
답변 답변 : ATMEGA128 UART,FND 연동 질문 댓글[1] master  22-06-20
질문 atmeg128 질문이요 댓글[1] 첨부파일공대생er  22-06-18
질문 atmega128 초음파 센서로 신호등 시간초 늘리기 서동씨  22-06-18
답변 답변 : atmega128 초음파 센서로 신호등 시간초… 댓글[1] master  22-06-18
질문 atmega128 댓글[2] 망경이  22-06-18
질문 앱인벤터 이용해서 수동 자동 할라고하는데 ..잘안됩니다… 댓글[1] 따랑해영  22-06-18
답변 질문 : 앱인벤터 이용해서 수동 자동 할라고하는데 ..… 댓글[1] 첨부파일따랑해영  22-06-19
답변 질문 : 앱인벤터 이용해서 수동 자동 할라고하는데 .… 첨부파일따랑해영  22-06-19
질문 서보모터와 초음파센서 댓글[1] 브링미히어  22-06-17
질문 LCD 도와주세요 ㅜㅠㅠㅠ 댓글[2] 첨부파일dentist22  22-06-17
질문 안녕하세요 atmega128 질문드리고 싶습니다. (자… 댓글[3] dlcldl  22-06-17
게시물 검색


Privacy Policy
MCU BASIC ⓒ 2017
PC버전