📄 uart_to_twi_m8_组合._c
字号:
/*****************************************************************
ICC-AVR application builder : 2005-8-19 14:40:53
Target : M8
Crystal: 7.3728Mhz
// Crystal: 4.6080Mhz
实验:做usart串行通讯实验
目的:了解及会使用usart串口
CPU:atmega8L
相关的5个寄存器:UCSRA,UCSRB,UCSRC,UDR,UBRR(UBRRH,UBRRL)
其中:UBRRH和UCSRC共用一个地址
******************************************************************/
/*配置:CKOPT=0,CKSEL3..0=1111,SUT1..0=11(65ms慢速上升电源)*/
#include <iom8v.h>
#include <macros.h>
//#define test
#define LED_ON 1
#define LED_OFF 0
#define IO_OUT_MAIN_LED 3 //PD3 pin1
#define IO_OUT_SLAVE_LED 2 //PD2 pin32
#define Main_Led_Off() PORTD |= BIT(IO_OUT_MAIN_LED)
#define Slave_Led_Off() PORTD |= BIT(IO_OUT_SLAVE_LED)
#define Main_Led_On() PORTD &= ~BIT(IO_OUT_MAIN_LED)
#define Slave_Led_On() PORTD &= ~BIT(IO_OUT_SLAVE_LED)
//usart
#define Fosc_4608 // 选择4.608M晶振crystal
#define true 1
#define false 0
#ifdef Fosc_73728
#define baudrate 47 //波特率为9600b/s 0<baudrate<255
#endif
#ifdef Fosc_4608
#define baudrate 29 //波特率为9600b/s 0<baudrate<255
#endif
/* UART Buffer Defines */
#define UART_RX_BUFFER_SIZE 127
#define UART_TX_BUFFER_SIZE 127
//TWI
#define START 0x08
#define RE_START 0x10
#define MT_SLA_ACK 0x18
#define MT_SLA_NOACK 0x20
#define MT_DATA_ACK 0x28
#define MT_DATA_NOACK 0x30
#define MR_SLA_ACK 0x40
#define MR_SLA_NOACK 0x48
#define MR_DATA_ACK 0x50
#define MR_DATA_NOACK 0x58
//常用TWI操作(主模式写和主模式读)
#define Start() (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN))
#define Stop() (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))
#define Wait() while(!(TWCR&(1<<TWINT)))WDR()
#define TestAck() (TWSR&0xf8)
#define SetAck() (TWCR|=(1<<TWEA))
#define SetNoAck() (TWCR&=~(1<<TWEA))
#define Twi() (TWCR=(1<<TWEA)|(1<<TWINT)|(1<<TWEN))//含有响应位
#define Write8Bit(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);}
#define DEVICE_ADR 0x22
void check_I2C(void);
void init_data(void);
void port_init(void);
void init_devices(void);
void timer0_init(void);
void check_watchdog(void);
void process_data_pack(void);
void twi_transmint(void);
void watchdog_init(void);
void check_main_led(void);
void check_slave_led(void);
void ascii_to_hex(void);
unsigned char Twi_Hex_Data[3];
unsigned char Twi_ASCI_Data[6];
unsigned char Twi_Write_Flag,Twi_Read_Flag;
unsigned char Twi_ASCI_Data_Flag,Twi_Hex_Data_Flag;
//LED指示灯
unsigned char Slave_Led_Status;
unsigned char Main_Led_Status,Cur_Main_Led_Status,Count_10ms;
//usart
unsigned char UART_RX_buff[UART_RX_BUFFER_SIZE];
unsigned char UART_TX_buff[UART_TX_BUFFER_SIZE];
unsigned char Rx_Flag;
unsigned char Rx_Temp,Rx_Count;
unsigned char Rx_Start_Pack_Flag,Rx_Over_Pack_Flag;
unsigned char Write_Error[5] = {'x','w','4','0','x'};
unsigned char Read_Error[5] = {'x','w','8','0','x'};
void main(void)
{
init_devices();
init_data();
USART_Transmit( "read go!" );//用来指示,是不是看门狗复位
while(1) //forever
{
//while(1);
UART_Receive();
// while(1)WDR();
check_watchdog();//喂狗
process_data_pack();//解包
twi_transmint();
//while(1)WDR();
check_main_led();
}
}
//>>>>>>>>>>>>>>>>>>>>>>>>解包
void process_data_pack(void)
{
unsigned char cnt,dat;
if(Rx_Over_Pack_Flag == true)
{
//从灯
Slave_Led_Status = LED_ON;
check_slave_led();//先让通讯亮一下
Rx_Over_Pack_Flag = false;
Slave_Led_Status = LED_OFF;
if(UART_RX_buff[1] == 0x57)
{
for(cnt =0;cnt<6;cnt++)
{
dat = UART_RX_buff[cnt+2];
if((dat >= 0x30)&&(dat <=0x39))
{
Twi_ASCI_Data[cnt] = dat - 0x30;
}
else if((dat>=0x41)&&(dat<=0x46))
{
Twi_ASCI_Data[cnt] = dat - 0x37;//如果是字母,那么减去0x37
}
}
ascii_to_hex();//组合成数据
Twi_Write_Flag = true;
}
if(UART_RX_buff[1] == 0x52)
{
for(cnt =0;cnt<4;cnt++)
{
dat = UART_RX_buff[cnt+2];
if((dat >= 0x30)&&(dat <=0x39))
{
Twi_ASCI_Data[cnt] = dat - 0x30;
}
else if((dat>=0x41)&&(dat<=0x46))
{
Twi_ASCI_Data[cnt] = dat - 0x37;//如果是字母,那么减去0x37
}
}
ascii_to_hex();
Twi_Read_Flag = true;
}
Twi_Hex_Data_Flag = true;
//处理完,先把数据放在UART_TX_buff[]绶冲区,且接收绶冲区清零
/*for(cnt=0;cnt<9;cnt++)
{
UART_TX_buff[cnt] = UART_RX_buff[cnt];
UART_RX_buff[cnt] = 0;
}*/
}
}
//继续解包,=>两个ASCII码组成一个数
void ascii_to_hex(void)
{
unsigned char cnt,i;
for(cnt=0,i=0;cnt<6;cnt++,cnt++,i++)
{
Twi_Hex_Data[i] = Twi_ASCI_Data[cnt+1];//先放ASCII的高位(四位)
Twi_Hex_Data[i] <<= 4;
Twi_Hex_Data[i] += Twi_ASCI_Data[cnt];
}
}
void hex_to_ascii(unsigned char dat)
{
unsigned char dat_buff;
dat_buff = dat;
dat = dat&0x0f;
if((dat>=0)&&(dat<=9))
{
dat += 0x30;
}
else
dat += 0x37;
UART_TX_buff[7] = dat;
dat = dat_buff;
dat >>= 4;
dat = dat&0x0f;
if((dat>=0)&&(dat<=9))
{
dat += 0x30;
}
else
dat += 0x37;
UART_TX_buff[8] = dat;
}
//<<<<<<<<<<<<<<<<<<<<<
/***********************************************************************
通用的hex转成ascii
************************************************************************/
unsigned char general_hex_to_ascii(unsigned char dat)
{
dat = dat & 0x0f;
if((dat >= 0)&&(dat <= 9))
{
dat = dat + 0x30;
}
else if((dat>='A')&&(dat<='F'))
{
dat += dat + 0x37;
}
return dat;
}
//>>>>>>>>>>>>>>>>做包
void twi_transmint(void)
{
unsigned char dat1,dat2;
unsigned char dat1_buff;
if(Twi_Hex_Data_Flag == true)
{
Twi_Hex_Data_Flag = false;
if(Twi_Write_Flag == true)
{
Twi_Write_Flag = false;
dat1 = twi_Write(Twi_Hex_Data[0],Twi_Hex_Data[1],Twi_Hex_Data[2]);
#ifdef test
dat1_buff = dat1;
dat1 >>= 4;
dat1 = dat1 & 0x0f;
dat1 = general_hex_to_ascii( dat1 );
USART_TransmitByte(dat1);
dat1 = dat1_buff;
dat1 = dat1 & 0x0f;
dat1 = general_hex_to_ascii( dat1 );
USART_TransmitByte(dat1);
#endif
if(dat1 == 0)
{
USART_Transmit(UART_RX_buff);//写成功
}
else
{
USART_Transmit(Write_Error);//写不成功
}
#ifdef test
USART_Transmit("ok!");
//while(1)WDR();
#endif
}
if(Twi_Read_Flag == true)
{
#ifdef test
USART_TransmitByte((Twi_Read_Flag+0x30));
USART_Transmit("yes or no?");
#endif
Twi_Read_Flag = false;
dat2 = twi_Read(Twi_Hex_Data[0],Twi_Hex_Data[1]);
if(dat2 == 0)
{
USART_Transmit(Read_Error);//读失败
#ifdef test
USART_Transmit("here!");
#endif
}
else
{
hex_to_ascii(dat2);//读成功 且读的数在dat2中
USART_Transmit(UART_RX_buff);
}
#ifdef test
USART_Transmit("verify again!");
#endif
}
}
}
void init_data(void)
{
Twi_Write_Flag = false;
Twi_Read_Flag = false;
Twi_Hex_Data_Flag = false;
Twi_ASCI_Data_Flag = false;
Slave_Led_Status = LED_OFF;
Main_Led_Status = LED_OFF;
Cur_Main_Led_Status= LED_OFF;
Count_10ms = 0;
WDR();
}
void port_init(void)
{
PORTB = 0x3F;
DDRB = 0x00;
PORTC = 0x4F; //m103 output only
DDRC = 0x00;
PORTD = 0xFC;
DDRD = 0x00;
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
uart0_init();
twi_init();
timer0_init();
watchdog_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void check_watchdog(void)
{
WDR();//喂狗
}
void watchdog_init(void)
{
WDR();//看门狗计数清零
WDTCR=((1<<WDE)|(1<<WDP2)|(1<<WDP0));//64K分频,0.52S
//WDIE是看门狗中断使能,WDE看门狗使能 101 512k
}
//TIMER0 initialize - prescale:256
// desired value: 100Hz
// actual value: 100.000Hz (0.0%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x4C; //set count
TCCR0 = 0x04; //start timer
}
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0 = 0x4C; //reload counter value
//主灯
Count_10ms++;
if((Count_10ms>0)&&(Count_10ms<5))
{
Cur_Main_Led_Status = LED_ON;
}
if((Count_10ms>5)&&(Count_10ms<10))
{
Cur_Main_Led_Status = LED_OFF;
}
}
void check_main_led(void)
{
if(Main_Led_Status != Cur_Main_Led_Status)
{
if(Main_Led_Status == LED_ON) Main_Led_Off();
else Main_Led_On();
Main_Led_Status = Cur_Main_Led_Status;
}
}
void check_slave_led(void)
{
if(Slave_Led_Status == LED_ON)
{
Slave_Led_On();
}
else
{
Slave_Led_Off();
}
}
void twi_init(void)
{
TWCR= 0X00; //disable twi
TWBR= 0x20; //set bit rate
TWSR= 0x00; //set prescale
TWAR= DEVICE_ADR; //set slave address
TWCR= 0x44; //enable twi 置位TWEA,TWEN TWIE
}
/******************************************
I2C总线写一个字节
返回0: 写成功
返回错误状态字:写失败
*******************************************/
unsigned char twi_Write(unsigned char wr_device_add,unsigned char RamAddress,unsigned char Wdata)
{
Start();//I2C启动
Wait(); //等TWINT置位
if(TestAck()!=START) return TestAck();//ACK
Write8Bit(wr_device_add);//写I2C从器件地址和写方式
Wait();
if(TestAck()!=MT_SLA_ACK) return TestAck();//ACK
Write8Bit(RamAddress);//写RAM地址
Wait();
if(TestAck()!=MT_DATA_ACK) return TestAck();//ACK
Write8Bit(Wdata);//写数据
Wait();
if(TestAck()!=MT_DATA_ACK) return TestAck();//ACK
Stop();//I2C停止
delay_ms(10);//延时等写完
return 0;
}
/******************************************
I2C总线读一个字节
如果读失败也返回0
*******************************************/
unsigned char twi_Read(unsigned char rd_device_add,unsigned char RamAddress)
{
unsigned char temp;
Start();//I2C启动
Wait();
if (TestAck()!=START) return 0;//ACK
Write8Bit(rd_device_add);//写I2C从器件地址和写方式
Wait();
if (TestAck()!=MT_SLA_ACK) return 0;//ACK
Write8Bit(RamAddress);//写RAM地址
Wait();
if (TestAck()!=MT_DATA_ACK) return 0;
Start();//I2C重新启动
Wait();
if (TestAck()!=RE_START) return 0;
Write8Bit(rd_device_add+1);//写I2C从器件地址和读方式
Wait();
if(TestAck()!=MR_SLA_ACK) return 0;//ACK
Twi();//启动主I2C读方式,且设为准备响应
Wait();
if(TestAck()!=MR_DATA_NOACK) return 0;//ACK
temp=TWDR;//读取I2C接收数据
Stop();//I2C停止
return temp;
}
#pragma interrupt_handler uart0_rx_isr:12
void uart0_rx_isr(void)
{
//uart has received a character in UDR
UART_RX_buff[Rx_Count] = UDR;
Rx_Count = Rx_Count+1;
if(Rx_Count == 9)
{
Rx_Flag = true;
//USART_TransmitByte((Rx_Count+0x30));
Rx_Count = 0;
//上位机在这时候要停一会儿,才能发第二串数据
}
//USART_TransmitByte((Rx_Count+0x30));
}
//UART0 initialize
// desired baud rate: 9600
// actual: baud rate:9600 (0.0%)
// char size: 8 bit
// parity: Disabled
void uart0_init(void)
{
Rx_Count = 0;
Rx_Flag = false;
Rx_Start_Pack_Flag = false;
Rx_Over_Pack_Flag = false;
//本身的uart的初始化
UCSRB = 0x00; //disable while setting baud rate
//UCSRB[RXCIE,TXCIE,UDRIE,RXEN,TXEN,UCSZ2,RXB8,TXB8]
//Bit 7 – RXCIE: RX Complete Interrupt Enable
UCSRA = 0x00;
//UCSRA[RXC,TXC,UDRE,FE,DOR,PE,U2X,MPCM]
UCSRC = (BIT(URSEL)|BIT(UCSZ1)|BIT(UCSZ0));//设置成8位
//UCSRC[URSEL,UMSEL,UPM1,UPM0,USBS,UCSZ1,UCSZ0,UCPOL]
//位URSEL:寄存器选择("1"为UCSRC或"0"为UBRRH)
//位UMSEL:工作模式选择(0为异步,1为同步)
//位UPM1..0:为校验方式,硬件支持校验
//位USBS:停止位选择(0为一位,1为两位)
//位UCSZ0..2:发送位数选择(如果是8位:011)
//位UCPOL:时钟极性(只在同步模式使用,异步应置为"0")
UBRRL = baudrate; //set baud rate lo
UBRRH = 0x00; //set baud rate hi(设置波特率只用低四位,加起来一共12位)
//UBRR = baudrate; /* set the baud rate */
UCSRB = ((1<<RXCIE)|(1<<RXEN)|(1<<TXEN));
}
/************************************************************************
接收时采用中断方式,,,以"包"为单位接收(9个字符)
*************************************************************************/
void UART_Receive(void)
{
if(Rx_Flag == true)
{
Rx_Flag = false;
if((UART_RX_buff[0] == 0x58)&&(UART_RX_buff[8] == 0x58))//0x58 = 'w'
{
Rx_Over_Pack_Flag = true; //这个标志,可以让主函数去查
//Rx_Count = 0;//接收计数器清零
}
//USART_TransmitByte('p');//接收一包完,就发一个信号叫上机暂停发
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -