BASIC4MCU | 질문게시판 | CRC 체크 오류 확인...
페이지 정보
작성자 choi 작성일2020-12-01 17:13 조회4,331회 댓글4건본문
#include<stdio.h> //빌드완료
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#define USART_BAUDRATE 19200
#define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
#define U_C unsigned char
#define U_I unsigned int
#define U_L unsigned long
volatile uint8_t Timer1_Flag = 0; // Timer1 flag
volatile uint8_t RX_CNT;
uint8_t TX_BUF[8], RX_BUF[13];
uint16_t crc16, au16regs[4];
float RawData, CompData, SensData;
void TX1_CH(U_C ch) { while (!(UCSR1A & 0x20)); UDR1 = ch; } // 송신 1바이트
void TX1_STR(U_C* str) { while (*str)TX1_CH(*str++); } // 문자열 송신함수
//
ISR(USART1_RX_vect)
{
RX_BUF[RX_CNT++];
}
void USART1_Init(long baud)
{
//3. UBRR0은 16비트 레지스터이기 때문에 8비트씩 나누어서 넣어야 한다.
UBRR1H = (uint8_t)(UBRR_VALUE >> 8);
UBRR1L = (uint8_t)UBRR_VALUE;
//4. USART 설정
UCSR1C |= (1 << UCSZ10) | (1 << UCSZ11); //Charecter size : 8비트
UCSR1C &= ~(1 << USBS1); //stop bit : 1비트
UCSR1C &= ~((1 << UPM11) | (1 << UPM10)); // no parity mode
UCSR1B = 0b10011000; //enable interrupt
}
ISR(TIMER1_OVF_vect) { // interrupt service routine : interval 100ms
TCNT1 = 59286; // 65536-16MHz/256/10Hz = 65536 - 16000000/256/10Hz = 59286
Timer1_Flag = 1;
}
void Timer1_Init(void) { //avr 레지스터 확인 필요
TCNT1 = 0;
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 59286; // preload timer 65536-16MHz/256/10Hz = 65536 - 16000000/256/10 = 59286
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK |= (1 << TOIE1); // enable timer overflow interrupt
}
uint16_t CalcCRC16(uint8_t * cdata, uint16_t ilen) {
uint16_t AccumCRC16 = 0xffff;
uint8_t i, j;
for (j = 0; j < ilen; j++) {
i = (AccumCRC16 ^ *(cdata++)) & 255;
AccumCRC16 = ((AccumCRC16 >> 8) ^ TableCRC16[i]) & 0xffff;
}
return AccumCRC16;
}
uint8_t highByte(uint16_t Data)
{
return (Data >> 8) & 0xFF;
}
uint8_t lowByte(uint16_t Data)
{
return Data & 0xFF;
}
int8_t query(void) {
uint8_t i;
TX_BUF[0] = 0x01;
TX_BUF[1] = 0x03;
TX_BUF[2] = 0x00;
TX_BUF[3] = 0x01;
TX_BUF[4] = 0x00;
TX_BUF[5] = 0x04;
crc16 = CalcCRC16(TX_BUF, 6);
TX_BUF[6] = lowByte(crc16);
TX_BUF[7] = highByte(crc16);
for (i = 0; i < 8; i++) {
TX1_CH(TX_BUF[i]);
}
}
int main()
{
DDRG = 0x03;
USART1_Init(19200);
Timer1_Init();
sei();
while (1) {
if (Timer1_Flag) {
Timer1_Flag = 0;
RX_CNT = 0; //응답을 기다림 수신버퍼 비우기
query(); // send query : 100ms cycle
}
if (RX_CNT == 13) // mySerial.available 역할?
{
//char ch = RX_BUF[RX_CNT++]; //헷갈림 serial.read역할?
//특정 RX_BUF위치 값으로 센서값 변환
crc16 = CalcCRC16(RX_BUF, 11); // CRC calculation.
if (crc16 == (RX_BUF[11] | RX_BUF[12] << 8)) { // CRC verification.
au16regs[0] = (uint16_t)RX_BUF[3] << 8 | (uint16_t)RX_BUF[4];
au16regs[1] = (uint16_t)RX_BUF[5] << 8 | (uint16_t)RX_BUF[6];
au16regs[2] = (uint16_t)RX_BUF[7] << 8 | (uint16_t)RX_BUF[8];
au16regs[3] = (uint16_t)RX_BUF[9] << 8 | (uint16_t)RX_BUF[10];
RawData = (float)au16regs[0] * 0.02 - 273.15; // DataValue1 : Raw Temperature
CompData = (float)au16regs[1] * 0.02 - 273.15;// DataValue2 : Comp Temperature
//dummy = (float)au16regs[2]*0.02-273.15; // DataValue3 : reserved(not used)
SensData = (float)au16regs[3] * 0.02 - 273.15;// DataValue4 : Sensor package Temperature (Operating temperature)
if (CompData > 20) PORTG ^= 0x03;
}
RX_CNT = 0;
}
}
}
return 0;
}
다른곳은 PORTG LED를 통해 확인을 완료했는데 crc체크하는 부분ㅡ> if (crc16 == (RX_BUF[11] | RX_BUF[12] << 8)) { // CRC verification.
이 안쪽에 들어가질 않는거같은데.. 저쪽에 PORTG는 작동하지않아서요.
혹시 잘못된곳을 확인할수 있을까요??
댓글 4
조회수 4,331master님의 댓글
master 작성일
if (crc16 == (RX_BUF[11] | RX_BUF[12] << 8))
이 식을 조금 간단히 요약하면
if (조건1 | 조건2)
이 거죠?
| 연산자를 사용하면 안됩니다.
|| 연산자를 사용하세요
if (조건1 || 조건2)
choi님의 댓글
choi
아뇨 조건이아니고 비트연산입니다!
master님의 댓글
master
괄호를 보니 연산이 맞군요
master님의 댓글
master 작성일
crc16 연산이 제대로 되었는지 시리얼통신 등을 이용해서 확인하시고요
if (crc16 == (RX_BUF[11] | RX_BUF[12] << 8))
중간에 8비트로 연산되지 않도록 하려면
if (crc16 == ((uint16_t)RX_BUF[12] << 8 | RX_BUF[11] ))
쉬프트 하기 전에 형변환을 하면 확실합니다.(물론 이 연산으로 해결된다는 보장은 없습니다)