#include "stm32f10x.h"
#include "systeminit.h"
/*RS,RW,E 등의 정의*/
#define RS_H (GPIOA->BSRR =0x00000800) //RS=PA.11 =1
#define RS_L (GPIOA->BSRR =0x08000000) //RS=PA.11 =0
#define RW_H (GPIOA->BSRR =0x00000020) //RW=PA.5 =1
#define RW_L (GPIOA->BSRR =0x00200000) //RW=PA.5 =0
#define E_H (GPIOA->BSRR =0x00000010) //E=PA.4 =1
#define E_L (GPIOA->BSRR =0x00100000) //E=PA.4 =0
int a=0;
int i=0;
float duty = 1500;
unsigned char AD_val2, AD_val;
void ALLTHE_ANNOUNCE(void) {
RCC->APB2ENR =0X0000020D; //GPIOA,GPIOB에 RCC 클럭 공급 , AFIO ON, ADC1
GPIOB->CRH =0x33333333; //GPIO_E(15:8)를 50MHz push pull 출력으로
GPIOA->CRH =0x00003000; //GPIO_A(11,5,4)를 50MHz PP 출력으로
GPIOA->CRL =0x0B330003; // PA0 50MHz push pull 출력 LED , PA1 = analog input 채널1 지정, PA4 5 = LCD, PA6 = 서모보터
RCC->CFGR = 0x001F8402; //시스템클럭 36MHz, APB1 클럭 18MHz, APB2 클럭 36MHz로 하기 위한
RCC->CR = 0x01010082; //RCC_CFGR와 RCC_CR의 설정
RCC->APB1ENR = 0x00000003; //timer2, timer3,clock enable
}
void adc_0(void) {
/*ADC1 구성*/
ADC1->CR1 = 0x00000000; //Indefendent mode(DUALMODE=0),EOC인터럽트 disable(EOCIE=0),스캔 disable(SCAN=0)
ADC1->CR2 = 0x001E0002; //external event에 의한 변환이되,트리거는 SWSTART(EXTTRIG=1,EXTSEL=7)
//연속변환(CONT=1),우측배치(ALIGN=0)
ADC1->SQR1 &= 0xFF0FFFFF; //변환채채널 수=1(L=0)
ADC1->SMPR2|= (3<< 5); //샘플 시간=55.5 cycle(SMP1=5)
ADC1->SQR3 |= (1<< 0); //채널 1를 첫번째로 변환(SQ1=1)
/*ADC on*/
ADC1->CR2 |= 0x00000001; //ADC on(ADON=1)
/*눈금 보정*/
ADC1->CR2 |= 0x00000008;
while (ADC1->CR2 & 0x00000008);//reset이 끝날 때까지 대기
ADC1->CR2 |= 0x00000004; //보정 시작
while (ADC1->CR2 & 0x00000004);//보정이 끝날 때까지 대기
/*변환 시작*/
ADC1->CR2 |= 0x00400000; //SW에 의한 정규변환 시작
/*AD변환이 끝났는지를 보고, AD변환값을 읽어서 전압값으로 고친다*/
while (!(ADC1->SR & 0x00000002)); //EOC=1? 변환이 끝났는가?
AD_val = ADC1->DR & 0xFFF; //yes이면 변환값을 읽어서
AD_val = (3.3 * AD_val*1000) / (4096*100); // ADC기준전압=3.3V: 4096=12비트 AD 변환이므로
//원래 AD_val = (3.3 * AD_val) / 4096인데, 나눗셈에서 소수부분이 짤려지는 것 때문에
//1000을 곱하고,100으로 나누어 소숫점 아래 한자리를 표시할 수 있게 함
/*AD변환값 AD_val를 각 단위별 AD_val BCD로 바꾼다*/
AD_val2 = '0'+ (AD_val%100)/10; //AD_val의 10단위 BCD
if(AD_val2!=49) {
GPIOA->ODR = 0X00;
}
else if(AD_val2==49){
GPIOA->ODR = 0X01;
}
}
/*인터럽트 허용*/
void interrupt_1(void){
TIM2->DIER = 0x0001; /* interrupt on update, TIM_DIER_UIE=0x0001 */
NVIC_SetPriority(TIM2_IRQn,(1<<__NVIC_PRIO_BITS)-1); //set priority to 1
NVIC_EnableIRQ(TIM2_IRQn);
TIM2->EGR = 0x0001; //TIM_EGR_UG;
}
/*(us*마이크로) 초 지연루틴*/
void Delay_us(unsigned int us){ //(us*마이크로) 초 마큼 지연
volatile unsigned int ncount=1*us;
for(; ncount !=0; ncount--);
}
/*(ms*미리) 초 지연루틴*/
void Delay_ms(unsigned int ms) { //(ms*미리) 초 마큼 지연
volatile unsigned int ncount=4000*ms;
for(; ncount !=0; ncount--);
}
/*LCD에 명령을 기록하는 루틴*/
void write_cmd(u8 cmd) {
u16 iu16;
Delay_ms(5); //명령을 할 수 있을 때까지 기다림( busy() 대용임)
RS_L; //RS=0(명령 모드), R/W=0(기록 모드), E=1(E펄스)
RW_L;
E_H; //아래 E_L과 함께 E펄스(명령 앞뒤엔 이것이 있어야 함)
//E가 high인 경우에만 명령을 할 수 있음
iu16 = (u16)(cmd << 8); //하위 바이트에 있는 명령 cmd를 상위 바이트로 옮겨셔
GPIOB->ODR = iu16; //GPIOG_ODR의 상위 바이트(비트 15:8)를 통하여 IR에 기록한다
Delay_ms(2); //동작시간
E_L;
}
/*LCD에 데이터를 기록하는 루틴*/
void write_char(u8 data) {
u16 du16;
RS_H; //RS=1(데이터 모드), R/W=0(기록 모드), E=1(E펄스)
RW_L;
E_H;
du16 = (u16) (data << 8); //하위 바이트에 있는 문자데이터 data를 상위 바이트로 옮겨서
GPIOB->ODR = du16; //GPIOG_ODR의 상위 바이트(비트 15:8)를 통하여 DR에 기록한다
Delay_ms(2);
E_L;
}
/*LCD 초기화 루틴*/
void init_LCD(void) {
Delay_ms(16);
ALLTHE_ANNOUNCE(); //앞에서 정의한 LCD 관계 레지스터들의 값
write_cmd(0x38); // FUNCTION SET 명령
Delay_ms(5); // 4.1msec 지연
write_cmd(0x38); // FUNCTION SET 명령
Delay_us(120);
write_cmd(0x38); // FUNCTION SET 명령
Delay_us(250);
write_cmd(0x38); // FUNCTION SET 명령, 8비트 interface
write_cmd(0x08); // DISPLAY OFF 명령
write_cmd(0x0C); // DISPLAY ON 명령
write_cmd(0x01); // CLEAR DISPLAY 명령
write_cmd(0x06); // ENTRY MODE SET 명령
}
/* TIM2 1초 주기 */
void sec_1(void){
TIM2->CR1 = 0;
TIM2->CR2 = 0;
TIM2->CNT = 0; //timer2 counter의 초기화
TIM2->SR = 0; //clear FLAG
TIM2->PSC = 36000; //prescaler, 36000000/36000=1000(Hz)
TIM2->ARR = 1000 -1; //period, 1000/1000=1(Hz)=1(Sec)
}
/* 1초로 1주일 */
void TIM2_IRQHandler(void){
TIM2->SR = 0;
i++;
a++;
if(i<=9){
if(i==1){
init_LCD(); // LCD 초기화
}
u8 g;
u8 table1[16]="TODAY IS SUNDAY " ; //LCD에 표시할 문자데이터의 테이블
u8 table2[16]="NEXT IS MONDAY ";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(g=0; g<16; g++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table1[g]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(g=0; g<16; g++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table2[g]);
}
}
else if(10<=i && i<=15){
u8 h;
u8 table3[16]="TODAY IS MONDAY ";
u8 table4[16]="NEXT IS TUESDAY ";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(h=0; h<16; h++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table3[h]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(h=0; h<16; h++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table4[h]);
}
}
else if(16<=i && i<=176400){
u8 j;
u8 table5[16]="TODAY IS TUESDAY";
u8 table6[17]="NEXT IS WEDNESDAY";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(j=0; j<16; j++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table5[j]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(j=0; j<17; j++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table6[j]);
}
}
else if(176400<=i && i<=262800){
u8 k;
u8 table7[18]="TODAY IS WEDNESDAY";
u8 table8[16]="NEXT IS THURSDAY";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(k=0; k<16; k++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table7[k]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(k=0; k<16; k++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table8[k]);
}
}
else if(262800<=i && i<=349200){
u8 l;
u8 table9[17]="TODAY IS THURSDAY";
u8 table10[14]="NEXT IS FRIDAY";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(l=0; l<17; l++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table9[l]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(l=0; l<14; l++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table10[l]);
}
}
else if(349200<=i && i<=435600){
u8 m;
u8 table11[15]="TODAY IS FRIDAY";
u8 table12[16]="NEXT IS SATURDAY";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(m=0; m<15; m++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table11[m]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(m=0; m<16; m++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table12[m]);
}
}
else if(435600<=i && i<=522000){
u8 n;
u8 table13[17]="TODAY IS SATURDAY";
u8 table14[14]="NEXT IS SUNDAY";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(n=0; n<16; n++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table13[n]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(n=0; n<14; n++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table14[n]);
}
}
else if(522000<=i && i<=604800){
u8 o;
u8 table1[16]="TODAY IS SUNDAY "; //LCD에 표시할 문자데이터의 테이블
u8 table2[16]="NEXT IS MONDAY ";
write_cmd(0x80); // 제 1라인의 최초번지(DDRAM의 0번지)를 지정하고
for(o=0; o<16; o++) { // table_1에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table1[o]);
}
write_cmd(0xC0); // 제 2라인의 최초번지를 지정하고
for(o=0; o<16; o++) { // table_2에 있는 문자데이터를 차례로 불러 지정된 라인에 기록한다
write_char(table2[o]);
}
if (i==604800){
i=0;
}
}
if(a==3000){
duty= duty-600;
}
else if(a==3001){
duty=duty+600;
}
else if(a==3002){
a=0;
}
TIM3->CCR1 = (float)duty;
}
/* TIM3 서보모터 */
void servomotor_timer34(void) {
/*출력포트 설정*/
TIM3->CR1 = 0X0080; //ARPE=1(Aoto-reload preload register 활성화),CKD=00(clock division 없음),
//DIR=0(up counter),CMS=00(edge aligned mode)
TIM3->PSC = 36; //카운터 클럭=36MHz/(36)=1000000Hz
/*듀티비=7.5%의 PWM을 내기 위한 TIM3 설정*/
TIM3->ARR = 20000 -1; //TIM3주파수=TIM3 couter clock/(TIM3_ARR+1)=1000000Hz/20000=50Hz; ARR=펄스폭
TIM3->CCR1 = 1500; //TIM3_CNT duty cycle =[TIM3_CCR1/(TIM3_ARR+1)]*100
/*PWM 모드 설정*/
TIM3->CCER = 0x0000; //CCMR1 설정을 위해 필요함
TIM3->CCMR1 = 0x0068; //OC1M=110(PWM mode 1), OC1PE=1(enable preload register:주기적인 펄스 가능)
/*카운터와 PWM 활성화, 초기화*/
TIM3->CR1 |= 0x0001; //TIM3 enable
TIM3->CCER |= 0x0001; //CC1E=1(TIM_OutputState enable: OC1출력을 output핀으로 송출 가능)
TIM3->EGR = 0x0001; //UG(카운터 초기화, 레지스터들 update)
}
int main(void){
ALLTHE_ANNOUNCE();
/*1초를 위한 타이머 설정*/
sec_1();
servomotor_timer34();
interrupt_1();
/*카운팅 시작*/
TIM2->CR1 = 0x0001; //upcount,timer2 counting 시작
adc_0();
}
댓글 영역