高级数据链路控制(HDLC,Highlevel Data Link Control)规程是由国际标准化组织开发,面向比特同步的数据链路层协议。随着ARM处理器市场的成熟, ARM处理器上的高级数据链路控制器外设,几乎涵盖了HDLC规程常用的大部分子集。随着处理能力的提高,在ARM的底层对HDLC通信过程进行控制,具有成本低、灵活性好、便于扩展为操作系统上的应用程序等优点。
1STR71X系列的数据链路控制器
1.1STR71X的芯片介绍
STR71X系列是基于16/32位 ARM7TDMI内核的微控制器。该系列中的所有器件都包含片上高速单电压Flash存储器和高速RAM存储器。除了HDLC同步通信接口外,还提供了I2C、UART、BSPI、USB2.0、CAN接口等,极大地丰富了该系列在通信、网络等方面的控制能力。
1.2STR71X的HDLC模块介绍
STR71X系列上的高级数据链路控制器支持全双工操作,能够自动完成标志的设置、零位的检测、校验序列(FCS,Frame Check Sequence)的产生和校验;32位可屏蔽地址区域识别,3种可供选择的时钟,支持NRZ、NRZI、FM0或MANCHESTER数据编码模式,支持时钟恢复的数字锁相环(DPLL);内部含1个8位波特率生成器,2个128字节RAM缓冲器。实际应用中,fm0数据编码模式下,可以实现250 kb/s的数据收发。
1.3STR71X系列采用的HDLC帧的格式
STR71X的HDLC模块中数据是以帧为单位发送的。STR71X系列采用的HDLC的帧格式如下:

前(后)同步码:在发送器使能,且HDLC_TCTL中的前同步码发送使能开启的情况下,当把要传送的数据的字节数写入寄存器时,HDLC模块就开始发送0~16位的前同步码。
标志序列:采用“0111 1110” 为标志序列,所有的帧必须以“0111 1110”标志开始和结束。标志的检测和插入由HDLC模块自动完成。在传送的数据中,“0”后面跟随连续的6个“1”再跟一个“0”,就会被模块识别为标志。一个标志可以同时作为一个帧的开始标志和下一个帧的结束标志。
地址序列:STR71X有8组地址寄存器,通过设置可以实现32位可屏蔽私有地址域的识别,或者4字节的可屏蔽组地址域的识别(后者用于广播传送模式)。
信息序列:需要传送的数据或者字符。
校验序列:FCS域对标志位和插入的“0”以外的数据,进行循环冗余校验,采用CCITT(g(x)=16+X12+X5+1)对地址域,字节数据和FCS域数据生成CRC编码。接收方根据该编码进行检错,但不纠错。如果报错,将丢弃该帧。
零插入:为了保证标志码“0111 1110”不在帧的内部出现,STR71X采用硬件自动实现“零插入”。该法在发送端监视除标志码以外的所有字段,当发现有连续5个“1”出现时,便在其后添加一个“0”;在接收端,连续的5个“1”后面的“0”自动被删除。
帧间时间填充: 可以选择为发送标志,或者发送空闲状态。
2STR71X系列中HDLC模块配置
HDLC模块发送和接收可以有3种时钟配置: PLL2输出,PCLK1和DPLL。时钟配置框图如图1所示。

图1时钟配置框图
HDLC控制器可以处理NRZ、NRZI、FM0、MANCHESTER编码。编解码方式可以独立选择,分别由HDLC_TCTL和HDLC_RCTL控制。使用PLL2为时钟源时,HDLC模块只能运行在NRZ和NRZI模式。
3STR71X系列中HDLC模块编程
3.1开启外设寄存器的访问及配置编译环境
根据使用到的外设,编辑71x_conf.h文件,设定为:#define _HDLC,#define _GPIO,#define _TIM。去掉DEBUG注释屏蔽标记,允许在监视窗口查看外设寄存器。
将STR71X系列的集成软件函数库添加到编译环境下,并且按照STR71X的使用说明配置编译环境。
3.2发送接收环境的设置
① 配置不同的分频系数,产生适当的操作频率,配置HDLC的时钟为PLL2的输出。
RCCU_Div2Config (ENABLE);//OSC=16 MHz,将其二分频
RCCU_PLL1Config(RCCU_PLL1_Mul_12, RCCU_Div_2); //RCLK=48 MHz
RCCU_RCLKSourceConfig (RCCU_PLL1_Output);
RCCU_MCLKConfig(RCCU_DEFAULT);//MCLK=48 MHz,为内核和存储器供电
RCCU_PCLKConfig(RCCU_Div_2);//PCLK2=24 MHz,为APB2 供电
RCCU_FCLKConfig(RCCU_Div_2);//PCLK1=24 MHz,为APB1供电
/*设置定时器2的脉宽调制模式*/
TIM_ClockSourceConfig (TIM2, TIM_INTERNAL );
TIM_PrescalerConfig (TIM2,10 ); //24 MHz/77 = 312 kHz
TIM_PWMOModeConfig (TIM2,0x7,TIM_LOW,0x7,TIM_HIGH); //方波
TIM_CounterConfig(TIM2, TIM_START);
RCCU_PLL2Config(RCCU_PLL2_Mul_12, RCCU_Div_2);//设置HDLC的时钟为PLL2输出,1 MHz
HDLC_XmitClockSourceConfig(HDLC_HTXCKSource);//使用PLL2的输出为发送时钟源
HDLC_XmitBaudrateConfig(0);//使用时钟,不分频
HDLC_RecvClockSourceConfig(HDLC_HRXCK);//使用PLL2的输出为接收时钟源
HDLC_RecvClockPrescalerConfig(0);//使用时钟,不分频
② 设置中断。
EIC_Init();
EIC_IRQChannelConfig(HDLC_IRQChannel, ENABLE);//HDLC中断使能
EIC_IRQChannelPriorityConfig(HDLC_IRQChannel, 1);
EIC_IRQConfig(ENABLE);
HDLC_ITconfig(HDLC_IMR_TMCM,ENABLE);//发送完成中断使能
HDLC_ITconfig(HDLC_IMR_TBEM,ENABLE);//发送缓冲中断使能
HDLC_ITconfig(HDLC_IMR_TDUM,ENABLE);//发送数据下溢中断使能
HDLC_ITconfig(HDLC_IMR_RBFM,ENABLE);//接收缓冲区满中断使能
HDLC_ITconfig(HDLC_IMR_RFOM,ENABLE);//接收帧上溢中断使能
HDLC_ITconfig(HDLC_IMR_RMCM,ENABLE);//接收消息完成中断使能
HDLC_ITconfig(HDLC_IMR_RMEM,ENABLE);//接收消息错误中断使能
③ 发送环境初始化。
HDLC_Init();
gpio_init();//根据拐角自己编写程序
④ 接收环境初始化。
/*地址设置*/
void HDLC_PLID(u32 PLID) {
u8 *p=(u8*) &PLID;
HDLC﹥PARL = (p[2]<<8) | p[3];
HDLC﹥PARH = (p[0]<<8) | p[1];
}
HDLC_Init_Recv(HDLC_PAE | HELC_R_NRZ);//初始化接收编码模式
*(u32*)HDLC_RECEIVEBUFFER_BASE_LO = 0;//置零接收缓冲器
⑤ 初始化完成,关闭发送。
HDLC_Xmit_Control(DISABLE);
3.3发送过程和接收过程
利用库函数将数据写入缓冲区,当TEN置位时,写入需要传送的数据字节数。按如下方法配置好中断函数,就可以实现中断模式的传送。
void HDLC_IRQHandler(void) {
EIC_IRQChannelConfig(HDLC_IRQChannel, DISABLE);
if(HDLC﹥ISR & HDLC_RME) {
HDLC﹥ISR &= ~HDLC_RME;
errCount++;
HDLC﹥PCR = 1;
}
else if(HDLC﹥ISR & HDLC_RMC) {
HDLC_ClearInterruptStatus(HDLC_RMC);
HDLC_Recv_Frame (RecvBuffer);
frameRecv += 1;
totalRecv = 0;
}
else if(HDLC﹥ISR & HDLC_RFO) {
HDLC﹥ISR &= ~(HDLC_RBF | HDLC_RFO);
HDLC﹥ISR &= ~HDLC_RMC;
HDLC﹥PCR = 1;
}
else if(HDLC﹥ISR & HDLC_TDU) {//发送数据下溢,发送失败
HDLC﹥ISR &= ~(HDLC_TDU|HDLC_TBE);
HDLC﹥PCR = 1;//置零,产生挂起序列。可以由定时器发动数据传送
errTDU++;
GPIO_BitWrite(GPIO1, 10, 1);
GPIO_Config(GPIO1, 0x0020, GPIO_IN_TRI_CMOS);
GPIO_BitWrite(GPIO1, 6, 0);
}
else if(HDLC﹥ISR & HDLC_TMC) {
HDLC﹥ISR &= ~HDLC_TMC;
transCount++;
while (HDLC_ReadPCRStatus(HDLC_TEN)==1) ;
HDLC_Xmit_Frame (XmitBuffer,200);
frameSend++;
}
else if(HDLC﹥ISR & HDLC_TBE) {
HDLC_Xmit_Frame (XmitBuffer, 64);
}
EIC_IRQChannelConfig(HDLC_IRQChannel, ENABLE);
}
3.4测试过程
编写串口程序,将接收到的数据用超级终端显示出来。利用串口将实验板数据传送到PC机,在Windows界面下,用系统自带的超级终端检验数据传输的正确性。
结语
HDLC规程透明传输、可靠性高,对于不同的使用需求有很好的灵活性。在没有操作系统的模式下,利用ST公司的硬件模块实现HDLC协议的传输,不仅可以减少不必要的开销,而且增强了对硬件直接应用的灵活性。