tag 标签: 串口扩展芯片

相关博文
  • 热度 12
    2012-5-9 12:40
    5725 次阅读|
    2 个评论
    最近一个项目需要用到3个串口,但是用的MCU只有2个串口,选择多串口的单片机成本太高,最后打算用串口扩展芯片VK3214扩展2个串口。 VK3214可以用单片机的一个串口扩展出4个子串口,每个子串口都可以单独设置波特率。 脚位图如下:   MRX,MTX分别接单片机一个串口的TX,RX。RXn,TXn 为扩展的4个子串口。 每个子串口有16字节的发送FIFO,16字节的接收FIFO。当发送FIFO触发点中断使能时,发送FIFO中的数据小于设定的触发点时产生相应的中断。当接收FIFO触发点中断使能时,接收FIFO中的数据大于设定的触发点时产生相应的中断。 中断脚IRQ低电平有效,注意不是下降沿有效。IRQ接单片机的中断脚,中断脚接单片机的外部中断脚INT,INT要设置为低电平有效。因为是低电平有效,在进入中断程序后,要禁止外部中断,中断处理完后再开外部中断。 例如当接收FIFO中断使能,触发点设置为1,那么在接收FIFO中的数据大于1时,IRQ变低,产生中断,此时进入中断程序,在中断程序中要读完FIFO中的全部数据,接收FIFO的数据变为0时,IRQ才变为高。如果没读完FIFO退出中断,IRQ仍会为低,退出中断后,马上又进入中断程序,导致其它程序不能执行。 初始化VK3214时,要初始化完后再使能单片机的外部中断,否则会因为IRQ一直为低,导致程序一直运行外部中断程序,其它程序无法运行。 初始化程序如下: void Vk3214_Init(void){           uchar i;        FREEDOG;        VK3214_RST=1;        delay(10);        VK3214_RST=0;        delay(10);        VK3214_RST=1;        delay(10);                      write_reg(1,SCTLR,0x38); //串口1波特率设置为9600,使能串口1               write_reg(2,SCTLR,0x38);//串口2ㄌ芈噬柚梦?600,使能串口1        //write_reg(3,SCTLR,0x30);//禁止串口3        //write_reg(4,SCTLR,0x30);//禁止串口4          //write_reg(0,SCONR,0x00);        //write_reg(1,SCONR,0x00);        //write_reg(2,SCONR,0x00);        //write_reg(3,SCONR,0x00);          //write_reg(0,SFWCR,0x00);        //write_reg(1,SFWCR,0x00);        //write_reg(2,SFWCR,0x00);        //write_reg(3,SFWCR,0x00);          write_reg(1,SFOCR,0xcf);//接收FIFO触点控制1BYTE        //i = read_reg(1, SFOCR);        //SENDCOM1(i,1);        write_reg(2,SFOCR,0xcf);        //write_reg(2,SFOCR,0xcc);          write_reg(1,SIER,0x01);//使能接收FIFO触点中断,禁止发送FIFO触点中断        write_reg(2,SIER,0x01);        //write_reg(2,SIER,0x00);        //write_reg(3,SIER,0x00);               //write_reg(0,SIFR,0x00);        //write_reg(1,SIFR,0x00);        //write_reg(2,SIFR,0x00);        //write_reg(3,SIFR,0x00);          write_reg(1,GIR,0X30);//使能串口1, 2中断               while(read_reg(1,SFSR))//读完串口1,2接收FIFO中的数据               read_reg(1,SFDR);        while(read_reg(2,SFSR))               read_reg(2,SFDR);        write_reg(1,GUCR,0X10);//主串口波特率设为38400               AUXR=0x14;///S2使用独立波特率发生器,S2波特率不加倍BRTX12设为1        BRT=0xf7;//0xee;//0xf7;//设置波特率38400        delay(10);        } 为保证及时接收到扩展串口的数据,接收FIFO触发点中断设置为1,即接收到1个字节就产生中断,发送因为是单片机控制,不用设置触发点中断。 //******************************************************************** void uart_sendByte(unsigned char dat) {        S2BUF=dat;        while(!(S2CON 0x02));                            //waite for data to transmit completely            S2CON = 0xFD; } //通过串口发送1个字节的数据,dat为发送的数据 //**************************************************************************   //*************************************************************************** unsigned char uart_recByte(void) {        unsigned char rec=0;        while(!(S2CON 0x01));                          //waite to recieve data in SBUF0        rec=S2BUF;            S2CON = 0xFE;        return rec; } //接收一个字节的数据,函数返回读取到的数据 //***************************************************************************   //*************************************************************************** unsigned char read_reg(unsigned char port,unsigned char reg) {        uchar i;        EX1 = 0; //此处关外部1中断,避免在读写寄存器时,串口芯片接收到数据引起外部中断,在外部中断调用相同的寄存器会导致死机        uart_sendByte(((port-1)4)+reg);        i =  uart_recByte();        EX1 = 1;        return i; } //读取寄存器的值,port为子串口的路数,reg为寄存器的地址,返回值是寄存器的值 //***************************************************************************   //**************************************************************************** void write_reg(unsigned char port,unsigned char reg,unsigned char dat) {        EX1 = 0;        uart_sendByte(0x80+((port-1)4)+reg);        uart_sendByte(dat);        EX1 = 1; } 从上面的函数可以看出,单片机的串口控制VK3214的串口,读写都是先发送VK3214的寄存器地址,然后再读写数据,所以如果单片机的串口和扩展的子串口的波特率设置成一样,会导致子串口接收FIFO溢出,再考虑到用单片机的一个串口控制2-4个子串口,所以单片机的串口波特率一定要是子串口波特率的倍数,我现在扩展2个串口,子串口的波特率为9600,所以我把单片机串口的波特率设置为38400,是子串口的4倍。倍数要考虑好,太慢会导致接收FIFO溢出,太快会导致发送FIFO的数据还没发出去,有送进来新的数据,发送FIFO溢出。 VK3214复位后根据外接的晶振,主,子串口都有默认的波特率,单片机上电后先把波特率设为和VK3214主串口波特率一样,初始化VK3214完成后,在改变VK3214的主串口波特率和单片机串口的波特率。见初始化程序的最后部分。   接下来关键的部分是外部中断程序的处理。程序如下: void Int1Init(void) interrupt 2 {        uchar x,i,j,z;        EX1 = 0;        uart_sendByte(GIR);        i=uart_recByte();        FREEDOG;        if(i0x01)        {               uart_sendByte((04)+SSR);               z=uart_recByte();               z=0x01;               while(z==0)               {                                                  uart_sendByte((04)+SFDR);                             com2rev = uart_recByte();                             FREEDOG;                             if(com2revidx=COM2_MAX)com2revidx=0;                             uart_sendByte((04)+SSR);                             z=uart_recByte();                             z=0x01;                                    }        }        if(i0x02)               {                      uart_sendByte((14)+SSR);               z=uart_recByte();               z=0x01;               while(z==0)               {                                                  uart_sendByte((14)+SFDR);                             com3rev = uart_recByte();                             FREEDOG;                             if(com3revidx=COM3_MAX)com3revidx=0;                             uart_sendByte((14)+SSR);                             z=uart_recByte();                             z=0x01;               }               } EX1 = 1;        } 进入中断后先判断是哪个子串口产生的中断,如果是子串口1产生的接收中断,那么读子串口1的寄存器SSR,看接收FIFO是否为空,不为空就一直读子串口1的接收FIFO,直到FIFO为空。中断程序中一定要把接收FIFO的数据读完,因为我设置的接收FIFO触发点数据为1。如果不读完退出中断,IRQ仍然会为低,还会继续进入中断程序。读完后,IRQ才变为高。 
相关资源