BASIC4MCU | 질문게시판 | 답변 : 사진과 구동 영상으로 다시 질문하겠습니다!
페이지 정보
작성자 master 작성일2019-12-27 22:00 조회6,780회 댓글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 Offvoid 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 Offvoid 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){ // 500msTCNT3H=0x85; TCNT3L=0xED;if(Volt10>=40){ // Vwarn=4.0VTCCR1A=0x40; TCCR1B=0x0a;if(cnt_bell==0){ cnt_bell=1; PORTA=0x00; OCR1A=2082; Command(HOME); LCD_String("fire!!!"); }else { cnt_bell=0; PORTA=0xff; OCR1A=2777; Command(HOME); LCD_String(" "); }}else{ TCCR1A=0x00; TCCR1B=0x0a; PORTA=0xff; adc_display(); }}//void main(void){DDRB=0x30; DDRA=0x80; PORTA=0xff;LCD_init();ADCSRA=0x87; adc_display();TCCR3B=0x04; TCNT3H=0x85; TCNT3L=0xED; ETIMSK=0x04; // 500msSREG=0x80;while(1){ADCSRA=0xC7; while(!(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=0xC7; while(!(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){ // 500msTCNT3H=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 main(void){DDRB=0xff;LCD_init(); degree_display();rot_value=rot_base;TCCR1A=0x82; TCCR1B=0x1B; ICR1=0x09c3; OCR1A=rot_value;TCCR3B=0x04; TCNT3H=0xE7; TCNT3L=0x96; ETIMSK=0x04; // 500msADCSRA=0x87;SREG=0x80;while(1){v_value();if (Volt10<=15){ rot_dir=1; rot_delta=rot_delta2; }else if(Volt10<=20){ rot_dir=1; rot_delta=rot_delta1; }else if(Volt10<=30){ rot_dir=2; OCR1A=rot_value; } // 센터else if(Volt10<=35){ rot_dir=0; rot_delta=rot_delta1; }else { rot_dir=0; rot_delta=rot_delta2; }}}LCD 코드는 문제없다고 하니 생략했습니다.
LCD 코드를 위로 올리고
인터럽트 함수를 아래에
메인을 제일 아래에 작성하면
함수 프로토타입을 생략가능한 것이 늘어납니다.
소스코드가 간단해지죠
LCD 출력을 sprintf를 사용해서 작성 했습니다.
댓글 2
조회수 6,780Busan님의 댓글
Busan 작성일
master님 답변 정말 감사드립니다. 그런데 제가 main 문을 2개를 써본 적이 없어서 잘 모르겠는데 저 코드를 그대로 쓰면
0 - 1.5V까지는 서보모터가 약하게 돌며
1.5V - 3V까지는 중간으로 돌며
3V - 4V가 되면 빠르게 돌면서
4V에 도달 시 화재로 판단하여 LED 점등(PA7 단자) 및 스피커 알람, LCD에 fire 점등이 되는 것인가요??
main문과 선언이 중복되요 오류가 발생하진 않나요??
두 코드를 취합해서 쓰고 싶은데 main문이 중복이되서요 ㅠㅠ
두 코드를 하나처럼 쓰고 싶은데 어떻게 구성해야할 지 몰라서 댓글 남깁니다.
master님의 댓글
master
소스코드를 합치지 않은 상태입니다.
심각한 오류를 체크 해드렸으니
각각 동작시켜서 제대로 동작하는지 확인하고
합쳐서 만들어보세요