1. 相关寄存器:
1. SCIBDH,SCIBDL:波特率寄存器(SCIBDH只有低5位有效)
波特率 = 总线频率 / (16 * SBR[12:0])
2. SCICR2: SCI控制寄存器2
位数 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
含义 |
TIE |
TCIE |
RIE |
ILIE |
TE |
RE |
RWU |
SBK |
复位值 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
TIE: 发送中断使能位。使能发送数据寄存器空标志(TDRE)来产生中断申请
TCIE: 发送完成中断使能位。使能发送完成标志(TC)来产生中断申请
RIE: 接收器满中断使能位
TE: 发送器使能位
RE: 接收器使能位
3. SCISR1: SCI状态寄存器1
位数 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
含义 |
TDRE |
TC |
RDRF |
IDLE |
OR |
NF |
FE |
PF |
复位值 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
TDRE: 发送数据寄存器空标志
TC: 发送完成标志
RDRF: 接收数据寄存器满标志
4. SCIDRL,(SCIDRH): SCI数据寄存器
2.寄存器使用注意事项:
1. TDRE(TC)复位值为1,因此将SCICR2的TIE(TCIE)置为1即可产生中断
2. TDRE,TC的清除方法:读SCISR1,然后写SCIDRL,注意,发送完最后一个字节之后,会产生中断,但因为这是最后一个字节,故不会写SCIDRL,中断标志仍然存在
3. RDRF的清除方法:读SCISR1,然后读SCIDRL。
3.示例函数;
说明:
1. 发送和接收都采用中断方式,以帧为基本处理单元,当接收到一帧完整数据时,置位接收标志,主程序不断查询接收标志,若接收标志置位,则调用接收处理函数解析接收到的帧。
2. 通信协议基本形式:帧头(1字节) +通信头(1字节) +通信数据长度(1字节) +通信数据+校验字(1字节)
通信头: 表示通信的内容
通信数据长度 = 通信数据长度 + 校验字长度
// ============================================================================ // SCI初始化程序 // 注:总线时钟为40MHZ // baudrate = 153600,即9600bytes/s 使能接收中断(实际:156250bps) // ============================================================================ void SCI_Init(void) { // SCI1 SCI1BDH = 0X00; // baud rate = bus clock / (16*SBR[12:0]) 波特率153600,SBR[12:0]= 16 = 0X0F; SCI1BDL = 0X0F; SCI1CR2 = 0x2C; // 接收使能,接收器满中断使能,发送使能 } // ============================================================================ // 发送数据请求函数 // 如果没有数据正在发送,则立即发送,如果有数据正在发送,则置位发送请求标志位 // 主流程不断查询发送请求标志位,若有该标志位,且没有数据正在发送则发送 // ============================================================================ void Send(byte commd) { SCI_Commd=commd; if(Status.Bits.Uart_R_Over==0) // 发送完成 { Send_1(); } else { Status.Bits.Uart_T_Commd=1; // 置位发送请求标志 } } // ============================================================================ // 发送函数 // Pre_Send():发送预处理函数,根据通信头(commd)内容处理发送缓冲区 // ============================================================================void Send_1(void) { Pre_Send(); Status.Bits.Uart_R_Over = 1; // 置位正在发送标志 SCI1CR2 |= 0x40; // 使能中断 }// ============================================================================ // 串口中断程序 // 中断接收和中断发送 // ============================================================================ interrupt void SCI1_INT(void) { static byte R_num = 0, R_curr = 0; // 接收数据总数和当前指针 static byte T_num = 0, T_curr = 0; // 发送数据总数和当前指针 if(SCI1SR1_RDRF == 1) // 接收中断 { Uart_R_Str[R_curr] = SCI1DRL; R_curr++; // 判断是否为帧头 if(R_curr == 1) { // 若不为帧头,复位指针 if(Uart_R_Str[0] != Frame_Header) { R_curr = 0; R_num = 0; } } if(R_curr == 3) // 第二字节,通信帧长度 R_num = Uart_R_Str[2]+1; // Uart_R_Str[1] 为通信帧长度 // 每接收一个数据,num减1,当num为0时,一帧数据接收完毕 if(R_num != 0) { R_num--; if(R_num == 0) { R_curr = 0; // 当前存储位置指向Uart_R_Str[0] Status.Bits.Uart_Status = 1; // 置Uart接收完一帧数据标志位 } } } // 发送中断 else if(SCI1SR1_TC == 1) // 发送完成标志 { // 最后一个字节发送完成 if(T_curr == Uart_T_Str[2]+3) { //SCI1CR2 &= 0XF7; // 关闭发送功能 SCI1CR2 &= 0xBF; T_curr = 0; // 复位数据指针 Status.Bits.Uart_R_Over = 0; // 发送完成 } else SCI1DRL = Uart_T_Str[T_curr++]; } } // ============================================================================ // 主程序 // ============================================================================ /******************************全局变量**************************/ volatile byte Uart_R_Str[Uart_R_Length]; // 串口接收数据缓冲区 volatile byte Uart_T_Str[Uart_T_Length]; // 串口发送数据缓冲区 /****************************************************************/ void main(void) { // 初始化代码 ... for(;;) { if(Status.Bits.Uart_Status) { Uart_Deal(); // 接收帧处理函数,功能:校验,解析帧。 } if(Status.Bits.Uart_T_Commd && (!Status.Bits.Uart_R_Over)) { Status.Bits.Uart_T_Commd = 0; // 清除发送请求命令位 Send_1(); // 发送 } // 其余代码 ... } }