天宁宁 发表于 6 天前

测试Ai8051芯片串口 按键控制只能发送一次



手上有USB转串口通讯线,还有一块圈圈的51板,上面有232接口
还有8个指示灯,八个按键,于是用八个按键来分别发送8个数据,
同时送P2口显示,烧录好程序调试,发现只能一次按键有效。

第一次按其中一个按键,会发送对应的数据,P2口指示灯也点亮,
第二次就没有反应了。
程序是根据官方例程修改的.串口发送不是就检测发送结束标志TI么,
然后TI=0.

             void PrintString1(u8 SSF)
            {
               SBUF=SSF;
               while(TI!=1);
               TI=0;   
            }


/*******************************************/
            #include   "..\..\comm\AI8051U.h"
            #include   "stdio.h"
            #include   "intrins.h"
            typedef      unsigned char    u8;
            typedef      unsigned int    u16;
            typedef      unsigned long    u32;
            #define      MAIN_Fosc      11059200L   //定义主时钟(精确计算115200波特率)
//==========================================================================
            #define      Baudrate1 (65536-MAIN_Fosc/9600/4)
            #define      UART1_BUF_LENGTH    128
            u8         TX1_Cnt;    //发送计数
            u8         RX1_Cnt;    //接收计数
            bit          B_TX1_Busy; //发送忙标志
            u8         RX1_Buffer; //接收缓冲
/*************本地函数声明    **************/
            void         UART1_config(u8 brt);   // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
/****************外部函数声明和外部变量声明 *****************/
            sbit         OutPut0=P2^0;                   //
            sbit         OutPut1=P2^1;                   //
            sbit         OutPut2=P2^2;                   //
            sbit         OutPut3=P2^3;                   //
            sbit         InttPut0=P1^0;                  //
            sbit         InttPut1=P1^1;                  //
            sbit         InttPut2=P1^2;                  //
            sbit         InttPut3=P1^3;                  //
            sbit         InttPut4=P1^4;                  //
            sbit         InttPut5=P1^5;                  //
            sbit         InttPut6=P1^6;                  //
            sbit         InttPut7=P1^7;                  //
            u8         kcounter,kstatus;               //按键计数标志 按键状态标志
/****************按键计数器状态寄存器归零*************/
            void RstKey()
            {
            kcounter=0;                        //按键计数器归零
            kstatus=0;                         //状态寄存器归零
            }
/*****************按键低电平检测函数*****************/
            void   LowVoltKey(void)            //按键计数器状态标志加一
            {
            kcounter++;                     
            kstatus++;   
            _nop_();                           //延时                  
            }
/*****************按键高电平检测函数*****************/
            void    HighVoltKey(void)          //按键计数器加一 状态标志归零
            {
            kcounter++;                        //按键计数器加一
            kstatus=0;                         //按键状态标志归零
            _nop_();                           //延时
            }
/*****************延时*****************/
            void Delay100ms(u16 x)            //
            {
            u16 i,j;
            for(i=0;i<x;i++)
            for(j=0;j<11000;j++);
            }
//========================================================================
// 函数: void PrintString1(u8 *puts)
// 描述: 串口1发送字符串函数。
// 参数: SSF
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void PrintString1(u8 SSF)
            {
               SBUF=SSF;
               while(TI!=1);
               TI=0;   
            }
//========================================================================
// 函数: SetTimer2Baudraye(u32 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void SetTimer2Baudraye(u32 dat)
            {
            T2R = 0;      //Timer stop
            T2_CT = 0;    //Timer2 set As Timer
            T2x12 = 1;    //Timer2 set as 1T mode
            T2H = (u8)(dat / 256);
            T2L = (u8)(dat % 256);
            ET2 = 0;    //禁止中断
            T2R = 1;      //Timer run enable
            }
//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void UART1_config(u8 brt)
            {
/*********** 波特率使用定时器2 *****************/
               if(brt == 2)
               {
               S1BRT = 1;    //S1 BRT Use Timer2;
               SetTimer2Baudraye(Baudrate1);
               }

    /*********** 波特率使用定时器1 *****************/
               else
               {
               TR1 = 0;
               S1BRT = 0;      //S1 BRT Use Timer1;
               T1_CT = 0;      //Timer1 set As Timer
               T1x12 = 1;      //Timer1 set as 1T mode
               TMOD &= ~0x30;//Timer1_16bitAutoReload;
               TH1 = (u8)(Baudrate1 / 256);
               TL1 = (u8)(Baudrate1 % 256);
               ET1 = 0;    //禁止中断
               TR1 = 1;
               }
/*************************************************/

               SCON = (SCON & 0x3f) | 0x40;    //UART1模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
//PS= 1;    //高优先级中断
               ES= 1;    //允许中断
               REN = 1;    //允许接收
               P_SW1 &= 0x3f;
               P_SW1 |= 0x00;      //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
               B_TX1_Busy = 0;
               TX1_Cnt = 0;
               RX1_Cnt = 0;
            }
//========================================================================
// 函数: void UART1_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void UART1_int (void) interrupt 4
            {
            if(RI)
               {
               RI = 0;
               RX1_Buffer = SBUF;
               if(++RX1_Cnt >= UART1_BUF_LENGTH)   RX1_Cnt = 0;
               }
               if(TI)
               {
               TI = 0;
               B_TX1_Busy = 0;
               }
            }
/******************** 主函数 **************************/
            void main(void)
            {
               WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
               EAXFR = 1; //扩展寄存器(XFR)访问使能
               CKCON = 0; //提高访问XRAM速度
               P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
               P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
               P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
               P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
               P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
               P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
               P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
               P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
               UART1_config(2);    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
               EA = 1;             //允许全局中断
               Delay100ms(5000);
               OutPut0=0;
               OutPut1=0;
               Delay100ms(5000);
               OutPut0=1;
               OutPut1=1;
               Delay100ms(5000);
               OutPut0=0;
               OutPut1=0;
                Delay100ms(5000);
               OutPut0=1;
               OutPut1=1;
            
               Delay100ms(5000);
               OutPut2=0;
               OutPut3=0;
               Delay100ms(5000);
               OutPut2=1;
               OutPut3=1;
               Delay100ms(5000);
               OutPut2=0;
               OutPut3=0;
               Delay100ms(5000);
               OutPut2=1;
                  OutPut3=1;
                while (1)
                {
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut0)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut0)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X01);
                P2=0X01;
                }
//1
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut1)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut1)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X02);
                P2=0X02;
                }
//2
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut2)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut2)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X04);
                P2=0X04;
                }
//3
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut3)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut3)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X08);
                P2=0X08;
                }
//4
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut4)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut4)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X10);
                P2=0X10;
                }
//5
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut5)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut5)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X20);
                P2=0X20;
                }
//6
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut6)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut6)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X40);
                P2=0X40;
                }
//7
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut7)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut7)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                PrintString1(0X80);
                P2=0X80;
                }
//8
            }               


      
   
}



国芯人工智能 发表于 6 天前

测试AI8051芯片串口功能时,发现按键控制只能发送一次的问题,可能是由于串口发送机制未正确重置或程序逻辑存在缺陷。根据提供的代码片段,PrintString1函数通过检测TI标志位判断发送是否完成,并在发送完成后将TI清零。然而,若程序中未正确处理中断或未重新初始化相关寄存器,可能导致后续按键无法触发串口发送。

建议检查以下几点:

1. 串口初始化配置:确保SCON寄存器正确配置为模式1(8位异步串行通信),并设置正确的波特率。
2. 中断使能:如果使用中断方式接收数据,需确保EA和ES中断使能位已打开。
3. TI标志位管理:在发送函数中,确认TI在每次发送后被正确清零,避免因标志位未复位导致后续发送失败。
4. 按键消抖处理:若按键未进行消抖处理,可能因按键抖动导致多次触发或误判。
5. 主循环逻辑:检查主循环中是否对按键状态进行了持续检测,确保每次按键都能被识别并触发发送操作。

通过以上调整,应能解决按键仅能发送一次的问题,提升串口通信的稳定性和可靠性。

[本文内容由国芯人工智能辅助生成,仅供参考]

乘风飞扬 发表于 6 天前

你使能了串口中断,并且在中断函数里有清除 TI 标志
如果发送完成先触发中断函数,在中断里清除了 TI,那么程序就会卡死在 while(TI!=1);
使能串口中断的话,标红函数里面的代码建议改成:
    B_TX1_Busy = 1;
    SBUF = SSF;
    while(B_TX1_Busy);

天宁宁 发表于 6 天前

乘风飞扬 发表于 2025-8-28 09:35
你使能了串口中断,并且在中断函数里有清除 TI 标志
如果发送完成先触发中断函数,在中断里清除了 TI,那么 ...

就是这样不结束才修改的

乘风飞扬 发表于 5 天前

天宁宁 发表于 2025-8-28 19:27
就是这样不结束才修改的

先直接用Ai8051U实验箱例程包里面的串口收发测试例子烧录到芯片里
将串口功能验证成功后再进行修改或者移植,避免问题越改越多。

天宁宁 发表于 5 天前


把接收部分函数删除可以发送了


/*******************************************/
            #include   "..\..\comm\AI8051U.h"
            #include   "stdio.h"
            #include   "intrins.h"
            typedef      unsigned char    u8;
            typedef      unsigned int    u16;
            typedef      unsigned long    u32;
            #define      MAIN_Fosc      11059200L   //定义主时钟(精确计算115200波特率)
//==========================================================================
            #define      Baudrate1 (65536-MAIN_Fosc/9600/4)
            #define      UART1_BUF_LENGTH    128
            u8         TX1_Cnt;    //发送计数
            u8         RX1_Cnt;    //接收计数
            bit          B_TX1_Busy; //发送忙标志
            u8         RX1_Buffer; //接收缓冲
/*************本地函数声明    **************/
            void         UART1_config(u8 brt);   // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
/****************外部函数声明和外部变量声明 *****************/
            sbit         OutPut0=P2^0;                  //
            sbit         InttPut0=P1^0;                  //
            sbit         InttPut1=P1^1;                  //
            sbit         InttPut2=P1^2;                  //
            sbit         InttPut3=P1^3;                  //
            sbit         InttPut4=P1^4;                  //
            sbit         InttPut5=P1^5;                  //
            sbit         InttPut6=P1^6;                  //
            sbit         InttPut7=P1^7;                  //
            u8         kcounter,kstatus;               //按键计数标志 按键状态标志
/****************按键计数器状态寄存器归零*************/
            void RstKey()
            {
            kcounter=0;                        //按键计数器归零
            kstatus=0;                         //状态寄存器归零
            }
/*****************按键低电平检测函数*****************/
            void   LowVoltKey(void)            //按键计数器状态标志加一
            {
            kcounter++;                     
            kstatus++;   
            _nop_();                           //延时                  
            }
/*****************按键高电平检测函数*****************/
            void    HighVoltKey(void)          //按键计数器加一 状态标志归零
            {
            kcounter++;                        //按键计数器加一
            kstatus=0;                         //按键状态标志归零
            _nop_();                           //延时
            }
//========================================================================
// 函数: void PrintString1(u8 *puts)
// 描述: 串口1发送字符串函数。
// 参数: SSF
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void SendHex(u8 SSF)
            {
               OutPut0=0;
               SBUF=SSF;
               while(TI!=1);
               TI=0;
               OutPut0=1;   
            }
//========================================================================
// 函数: SetTimer2Baudraye(u32 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void SetTimer2Baudraye(u32 dat)
            {
            T2R = 0;      //Timer stop
            T2_CT = 0;    //Timer2 set As Timer
            T2x12 = 1;    //Timer2 set as 1T mode
            T2H = (u8)(dat / 256);
            T2L = (u8)(dat % 256);
            ET2 = 0;    //禁止中断
            T2R = 1;      //Timer run enable
            }
//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
            void UART1_config(u8 brt)
            {
/*********** 波特率使用定时器2 *****************/
               if(brt == 2)
               {
               S1BRT = 1;    //S1 BRT Use Timer2;
               SetTimer2Baudraye(Baudrate1);
               }

    /*********** 波特率使用定时器1 *****************/
               else
               {
               TR1 = 0;
               S1BRT = 0;      //S1 BRT Use Timer1;
               T1_CT = 0;      //Timer1 set As Timer
               T1x12 = 1;      //Timer1 set as 1T mode
               TMOD &= ~0x30;//Timer1_16bitAutoReload;
               TH1 = (u8)(Baudrate1 / 256);
               TL1 = (u8)(Baudrate1 % 256);
               ET1 = 0;    //禁止中断
               TR1 = 1;
               }
/*************************************************/

               SCON=(SCON&0x3f)|0x40;    //UART1模式,0x00:同步移位输出,0x40:8位数据,可变波特率,0x80:9位数据,固定波特率,0xc0 9位数据,可变波特率
//PS= 1;    //高优先级中断
               ES= 1;    //允许中断
               REN = 1;    //允许接收
               P_SW1 &= 0x3f;
               P_SW1 |= 0x00;      //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
               B_TX1_Busy = 0;
               TX1_Cnt = 0;
               RX1_Cnt = 0;
            }
/******************** 主函数 **************************/
            void main(void)
            {
               WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
               EAXFR = 1; //扩展寄存器(XFR)访问使能
               CKCON = 0; //提高访问XRAM速度
               P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
               P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
               P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
               P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
               P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
               P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
               P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
               P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
               UART1_config(2);    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
               EA = 1;             //允许全局中断
               SendHex(0X11);
               SendHex(0X21);
               SendHex(0X31);
               while (1)
                {
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut0)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut0)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X01);
                P2=0X01;
                }
//1
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut1)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut1)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X02);
                P2=0X02;
                }
//2
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut2)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut2)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X04);
                P2=0X04;
                }
//3
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut3)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut3)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X08);
                P2=0X08;
                }
//4
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut4)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut4)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X10);
                P2=0X10;
                }
//5
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut5)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut5)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X20);
                P2=0X20;
                }
//6
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut6)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut6)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X40);
                P2=0X40;
                }
//7
                RstKey();
                for(;kcounter<5;)               //按键循环5次
                {
               if(!InttPut7)                      //按键低电平
               {
               LowVoltKey();
               }
               else if(~!InttPut7)               //按键高电平
               {
               HighVoltKey();
               }
                }
                if(kstatus>=4)                  /*按键状态标志大于等于3为有效值*/
                {                              /*循环检测 */
                SendHex(0X80);
                P2=0X80;
                }
//8
            }               


梁工 发表于 5 天前

逻辑错误,发送中断清除TI=0,发送查询TI==1,就会死在这里,应该改为:
void PrintString1(u8 SSF)
{
      SBUF = SSF;
      B_TX1_Busy = 1;   //标志忙
      while(B_TX1_Busy)   ;//等待发送完成
}
页: [1]
查看完整版本: 测试Ai8051芯片串口 按键控制只能发送一次