资讯详情

阮工的单片机编程经验集:如何做稳定单片机程序与上位机程序防卡顿,js等经验;阮丁远于20220614

阮工单片机编程经验集V2.1:如何做稳定单片机程序 , 阮丁远:

===================================================================

误把 3.3V步进输出端口Vcc即5V上,导致写w25q一直失败和混乱!

===================================================================

晶振可能太低,导致串口波特率误差过大,串口接收乱码经常发生,晶振可以提高到25mhz , 但也有可能是串口中断占更多cpu处理代码,导致串口中断,数据丢失!

但也可能在其他函数中 EA=0; _itoa(num,。。, EA=1;禁止间隙中断,导致串口中断功能丢失,导致串口字节丢失的概率bug

===================================================================

一个正式的环境,一个调试环境,实际上是公共的 类序列化 存储文件后,导致异常:

get_bytes_from_obj(p_装货确认_arr, log.get_cur_path() "/bakjindu/装货确认" index1.ToString() ".dat");

get_bytes_from_obj(监控距离队列, log.get_cur_path() "/bakjindu/监控距离队列" index1.ToString() ".dat");

,加is_sandbox.ToString() , 改为:

get_bytes_from_obj(p_装货确认_arr, log.get_cur_path() "/bakjindu/" is_sandbox.ToString() "装货确认" index1.ToString() ".dat");

get_bytes_from_obj(监控距离队列, log.get_cur_path() "/bakjindu/" is_sandbox.ToString() "监控距离队列" index1.ToString() ".dat");

===================================================================

data_geted_time_$rnd_varname_pre$后续赋值为0while(data_is_ok_$rnd_varname_pre$==0&&data_geted_time_$rnd_varname_pre$<=3200的直接 被sdcc优化器优化,直接变成while(1==1)卡死:,可以用volatile关键词:

volatile u8 data_is_ok_$rnd_varname_pre$=0;

volatile u32 data_geted_time_$rnd_varname_pre$=0;

...,

----------------------------------------------------

u8 get_updatw_$rnd_varname_pre$(){ data_is_ok_$rnd_varname_pre$=0; data_geted_time_$rnd_varname_pre$=0;

data_is_need_up_$rnd_varname_pre$=1; EA=1; //TI=0;RI=0; while(data_is_ok_$rnd_varname_pre$==0&&data_geted_time_$rnd_varname_pre$<=3200){ data_is_need_up_$rnd_varname_pre$=1 ; } return data_is_ok_$rnd_varname_pre$; }

===================================================================

如果单片机中断断中更新数据,如果在其他非中断中实时读取数据,则很容易更新数据到一半读取数据,导致编码混乱, 可以用缓存 原子操作即EA=0; 赋值。。。 EA=1;来解决

===================================================================

用java 启动命令运行java包时容易cmd卡住窗户,按回车继续运行。

改为用javaw:

javaw -jar meterservice0.jar --spring.profiles.active=prod

===================================================================

SDCC例如,使用定义变量 __code xxxxx或 __xdata ,

那么用extern还应添加引用

__code 或 __xdata :

比如extern __code xxxxxx

===================================================================

lcd当1602并口屏幕显示整数字时,如何解决偶尔的花屏

SDCC的 _ltoa等函数要先EA=0;可调用,否则进中断 后 ,结果值是乱码!,检查一切 加上类似的库函数EA=0;调用完再EA=1:

EA=0; _ltoa(num, temp1str, 10);//比_itoa范围大

EA=1;

===================================================================

加 :if(us100_count_$rnd_varname_pre$>260){ //防止累积,最终死机,因为进不去if(us100_count_$rnd_varname_pre$>170&&us100_count_$rnd_varname_pre$<250)了:

[$interrupt_1] @@int_num=#get_interrupt_num_set_code(group_xml,rand1,block_name,ref_complier,extinfo,"[($_xgm$value3),type=pin]")%

static u8 Ray_Flag_$rnd_varname_pre$=0; us100_enable_$rnd_varname_pre$=1; if(us100_count_$rnd_varname_pre$>110&&us100_count_$rnd_varname_pre$<160//9ms的低电平和4.5ms高电平为引导码,大于11ms即可,也即>110 { Ray_Flag_$rnd_varname_pre$=1;      //标志位写1         Ray_Read_bit_count_$rnd_varname_pre$=0;                        //接收到引导信号,编号归0、         //Ray_Read_Buffer_$rnd_varname_pre$[4]++;                        //遥控器按着不放,会连续发送N个引导信号     }

    if(us100_count_$rnd_varname_pre$>170&&us100_count_$rnd_varname_pre$<250)//0.565ms低电平和20MS高电平                 {         Ray_Flag_$rnd_varname_pre$=2;                                    //标志位写1         Ray_Read_bit_count2_$rnd_varname_pre$=0;                        //接收到引导信号,编号归0、         //Ray_Read_Buffer_$rnd_varname_pre$[4]++;                        //遥控器按着不放,会连续发送N个引导信号     }

        if(us100_count_$rnd_varname_pre$>260){ //防止一直累加,而最终死机,因为进入不了if(us100_count_$rnd_varname_pre$>170&&us100_count_$rnd_varname_pre$<250)了

           us100_enable_$rnd_varname_pre$=0;

               us100_count_$rnd_varname_pre$=0;

          }

    if(Ray_Flag_$rnd_varname_pre$==1)                                    //如果之前的信号是引导     {         Ray_bit_timer_Buffer_$rnd_varname_pre$[Ray_Read_bit_count_$rnd_varname_pre$]=us100_count_$rnd_varname_pre$;//把定时器走时变量,赋值给数组缓存         us100_count_$rnd_varname_pre$=0;                        //时间重新累计         Ray_Read_bit_count_$rnd_varname_pre$++;                        //编号自动增加1         if(Ray_Read_bit_count_$rnd_varname_pre$>=36)    //起始码+35位数据         {             Ray_Read_bit_count_$rnd_varname_pre$=0;                    //编号清0             us100_count_$rnd_varname_pre$=0;                    //时间重新累计             //Ray_Read_ok_$rnd_varname_pre$=1;                            //允许CPU执行解码功能             Ray_Flag_$rnd_varname_pre$=0;                                //标志为写0表示一帧红外接收已经完成了         }     }

    if(Ray_Flag_$rnd_varname_pre$==2)                                    //如果之前的信号是引导     {         Ray_bit_timer_Buffer2_$rnd_varname_pre$[Ray_Read_bit_count2_$rnd_varname_pre$]=us100_count_$rnd_varname_pre$;//把定时器走时变量,赋值给数组缓存         us100_count_$rnd_varname_pre$=0;                        //时间重新累计         Ray_Read_bit_count2_$rnd_varname_pre$++;                        //编号自动增加1         if(Ray_Read_bit_count2_$rnd_varname_pre$>=33)    //起始码+32位数         {             Ray_Read_bit_count2_$rnd_varname_pre$=0;                    //编号清0             us100_count_$rnd_varname_pre$=0;                    //时间重新累计             Ray_Read_ok_$rnd_varname_pre$=1;                            //允许CPU执行解码功能             Ray_Flag_$rnd_varname_pre$=0;                                //标志为写0表示一帧红外接收已经完成了                                           us100_enable_$rnd_varname_pre$=0;    //暂时关闭定时器0

        }     }

===================================================================

stc12c5a60s2:

    P0M0 = 0x00;

    P0M1 = 0x00; //P0口如果插着lcd1602,会导致P0不推挽输出的话就驱动不了led灯的怪问题

===================================================================

EA=0;//防止Ray_Read_user_data_$rnd_varname_pre$=Ray_Read_Buffer_$rnd_varname_pre$[2]的赋值被中途中断打乱而乱码  :

void Ray_Decode_Drive_$rnd_varname_pre$() {     u8 i,j,k=1,value=0,tempv;     if(Ray_Read_ok_$rnd_varname_pre$==1)//如果已经完成一帧红外 33个时间长度的保存     {

                EA=0;//防止Ray_Read_user_data_$rnd_varname_pre$=Ray_Read_Buffer_$rnd_varname_pre$[2]的赋值被中途中断打乱而乱码

        Ray_Read_ok_$rnd_varname_pre$=0;//取反,防止第二次进来         TR1=0;    //暂时关闭定时器0         for(i=0;i<4;i++)//一帧红外是四个字节         {             for(j=0;j<8;j++)//每个字节是8个时间长短             {                 value>>=1;//先左移后判断                 if(Ray_bit_timer_Buffer_$rnd_varname_pre$[k]>17)//此参数为定时器定时102us所选值                 {                     value=value|0x80;//如果这个位的时间大于17*102us,既1700us以上是数据1                 }                 else                 {                     value=value&0x7f;//否则 这个位的时间小于17*102us,既1700us以下是数据0                 }                 k++;//判断下一个bit时间             }             if(i==3)//如果是第三字节             {                 if(value!=Ray_Read_Buffer_$rnd_varname_pre$[3])    //如果新接收的第3字节和上次保存的第3字节不一样                 {                     Ray_Read_Buffer_$rnd_varname_pre$[4]=255;//说明换了按钮了                      Ray_Read_Buffer_$rnd_varname_pre$[5]=255;                 }                 if(value==Ray_Read_Buffer_$rnd_varname_pre$[3])    //如果新接收的第3字节和上次保存的第3字节完全一样                 {                     Ray_Read_Buffer_$rnd_varname_pre$[5]++;    //连按加加                     Ray_Read_Buffer_$rnd_varname_pre$[4]=255;//长按归0 (255+1之后是0)                 }             }             Ray_Read_Buffer_$rnd_varname_pre$[i]=value;//解码的字节拷贝给数组         }

                tempv=Ray_Read_Buffer_$rnd_varname_pre$[2];//防止Ray_Read_user_data_$rnd_varname_pre$=Ray_Read_Buffer_$rnd_varname_pre$[2]的赋值被中途中断打乱而乱码

                  if(tempv==(u8)(~Ray_Read_Buffer_$rnd_varname_pre$[3])    &&  Ray_Read_Buffer_$rnd_varname_pre$[0]==(u8)(~Ray_Read_Buffer_$rnd_varname_pre$[1])   ){

                      Ray_Read_user_data_$rnd_varname_pre$=tempv;  

                   }

                EA=1;

    } }

===================================================================

如果调用函数在别的c文件里时, 单片机 c语言里不在调用函数所在c文件里头部定义函数申明的话 可能会出奇怪现象

--

struct A a;

fun(a) 这样代入可能有怪问题

需要: fun(&a) 这样代入,

而fun定义为 fun(struct A * a1){

.......

}

=================================================================== c#里   

A a=new a();   

       ....     

      a=new a();

       .....

A a1=new a();

A a2=new  a();

A a=a1;   .....  

a=a2;

......  

A  b=a1;

的区别 ???

===================================================================

   小数转整数时未先四舍五入而导致的0.99999丢失的问题:

val=6.7,

乘以10后:

process_exped_val=66.9999980926514

(int)process_exped_val=66

        public static int V100_convert_to_int_with_math_round(double val)         {

            return (int)Math.Round(val, MidpointRounding.AwayFromZero); // 

        }

-------------------

或者 为 (int)Math.Round(val)而未加 MidpointRounding.AwayFromZero参数,而导致四舍五入异常!,比如漏电流始终偶尔校不准!

===================================================================

加 ,id ASC:

 SELECT * FROM kb0_ui WHERE  is_use_zengliang_tongji=1 AND kb0_idstr='t_yi1xek3dhp' AND dianwei_name='dianneng_zong' AND (ADDTIME  BETWEEN '2021/01/01 00:00:00' AND '2022/01/01 00:00:00') ORDER BY diff_value1  DESC ,id ASC LIMIT 0,22

 SELECT * FROM kb0_ui WHERE  is_use_zengliang_tongji=1 AND kb0_idstr='t_yi1xek3dhp' AND dianwei_name='dianneng_zong' AND (ADDTIME  BETWEEN '2021/01/01 00:00:00' AND '2022/01/01 00:00:00') ORDER BY diff_value1  DESC LIMIT 0,22

要快!!,

或者ORDER BY round(diff_value1,5)  DESC 也快

--------------------------------

  company_id LIKE '...' 反而比company_id ='...'要快,可能改为 company_id LIKE '...' 后主键索引变为了ADDTIME ,

explain 分析 key_len从171变小为 17了 :

 SELECT SUM(diff_value1) AS zong_diff1,date_hour_index FROM kb0_ui WHERE  is_use_zengliang_tongji=1 AND dianwei_name='dianneng_zong' AND (company_id LIKE 't_uolcoya67e')  AND (ADDTIME  >= '2021-11-04 00:00:00' ) AND ADDTIME <= '2021-11-04 23:59:59' GROUP BY date_hour_index

  SELECT SUM(diff_value1) AS zong_diff1,date_hour_index FROM kb0_ui WHERE  is_use_zengliang_tongji=1 AND dianwei_name='dianneng_zong' AND (company_id = 't_uolcoya67e')  AND (ADDTIME  >= '2021-11-04 00:00:00' ) AND ADDTIME <= '2021-11-04 23:59:59' GROUP BY date_hour_index

===================================================================

1.程序里涉及清空缓存文件时且可以选择自定义导出目录时,务必不要删除文件操作, 万一用户选择的是桌面或其他系统目录,则全当为垃圾缓存而被删除且不可恢复!!!

,在线升级前如果要删除老文件,那要保证安装目录 是含子目录  的特定名比如 c:\soft001 ,以防止误删其他文件和目录,比如万一安装在硬盘根目录

删除前最好做备份

2. 检查所有线程里有无return,防止意外return

=================================================================== 服务端所有时间日期格式化为 字符串时,统一格式设为 yyyy-MM-dd HH:mm:ss ,防止操作系统设置日期与区域的格式时影响这个格式,而发生意外格式 ===================================================================

MySql等里面的float字段只有7位有效数字,大数值时容易省略小数位而发生不准!,可以换为

double 字段或其他专用于金钱统计的字段

===================================================================

LMxxxx5.0的12-36V的转5V的dc-dc稳压芯片,输入脚必须并40V470uf的电解电容,特别是输入脚前串了防反接二极管时,不然容易烧管,可能是反向高电压无法通过防反接二极管

=================================================================== 如果串口 校验位为2,而设为1,会使奇偶校验位发生奇怪的异常,比如一个串口调试软件调试正常,而上位机收到很多 3f 3f 3f.....

===================================================================

多个线程里不要用 MessageBox之类,而要用变量标志,在其他单线程里 MessageBox,否则一出错就弹个不完消息框!!

===================================================================

所有检测步骤做成状态机式的,可以回退的,这样方便:比如电压输出没到位时,方便回退重试的,而不是死循环等待,也不方便停止按钮

=================================================================== 有些不稳定性是因为器件寿命,比如程序里错误的存在了每秒写flash 1000次的操作,则flash很快损坏!!! ,

对于频繁读入flash的操作,可以做个ram缓存区,修改flash和开机时才更新缓存。。。 ----------------------------

,另外上电时先要等待200ms至少,来上电稳定后再读取比如w25Q64的内容,不然没上电稳定就读,容易读出错码!!!

===================================================================

注意多个设备的通信协议调用的 crc16函数,有的是高字节在前,有的是低字节在前,如果公用一个 crc16函数,就会导致改掉一个,另一个就通信不通的现象

=================================================================== 关闭所有采集卡输入通道,防止切换电流源时跳闸而引发测跳闸时间时异常!:

            qiehuan_caiji_boxingABC(99);//V888,关闭所有采集卡输入通道,防止切换电流源时跳闸而引发测跳闸时间时异常!              ,另外再加异常跳闸时的重试合闸和重上电复位!!!

===================================================================

喂狗也是有讲究的,不要在可能重复产生中断的中断服务函数里面喂狗。 万一程序死翘翘了,但是中断可不会死,这时候在中断里面喂狗的话,程序就会在跑飞和中断服务函数中切换 ===================================================================

AD9里新建pcb时有时距离是三层板,导致布线时有些引脚怎么也不布的问题,删掉pcb中间层即可

=================================================================== 有的发生源有 2种读电压电流的接口,一种读设定值,另一种读实时值,判断电压到位没要读实时值那个接口!!!

===================================================================

对 关闭电压输出 等高风险的按钮事件,为保证100%实时响应,则用类似以下的机制,即传入第二个参数8,不然默认0,则按钮事件互斥:

            p_void p1 = () =>             {                               close_all_UI();                 libcls.MessageBoxw("已降源,请等待8秒!");//提示会有安全感             };

            setrun(p1,8);

---

            for (int i = 0; i < 9999; i++)              {                 ingsetrun[i] = 0;             }

--

        public delegate void p_void();

        int[] ingsetrun = new int[9999];

        public void setrun(p_void p1,int lock_index=0)         {

            if (ingsetrun[lock_index] == 1)             {

                return;

            }

            ingsetrun[lock_index] = 1;             try             {

                System.Threading.Thread pt1 = new System.Threading.Thread(new System.Threading.ThreadStart(p1));

                pt1.Start();

                //while (pt1.ThreadState == System.Threading.ThreadState.Running || pt1.ThreadState== System.Threading.ThreadState.Unstarted)

                while (pt1.IsAlive)                 {                     Application.DoEvents();                     System.Threading.Thread.Sleep(5);//10的话太卡,小点,因为Sleep太大的话退出等待要卡很久!!

                }

            }             catch             {

                ingsetrun[lock_index] = 0;             }             ingsetrun[lock_index] = 0;

        }

=================================================================== delegate          {里的return 的作用域问题:

       int reted1 = 0;             this.Invoke(new EventHandler(delegate          {              Form2_Vatcmd_shoudong_set_botelv_webbrower pwwin1 = new Form2_Vatcmd_shoudong_set_botelv_webbrower();              pwwin1.sss2 = "请手动设置波特率到115200,然后点保存参数并重启串口服务器!";              pwwin1.refwin1 = this;              if (pwwin1.ShowDialog() != System.Windows.Forms.DialogResult.OK)              {                  reted1 = 1;                  return;

             }          }));             if (reted1 == 1)             {

                return;

            }

=================================================================== 用委托和事件解决2个类相互引用的问题:

    //定义一个delegate委托       public delegate void read_change_event_ruan_func_ptr(int index1);     //定义事件,类型为上面定义的read_change_event_ruan_func_ptr委托       public event read_change_event_ruan_func_ptr Onread1;  

    public void read_change_event_ruan(int index1)     {

        Onread1(index1);

    }

,另一个类里:

  m_processor.Onread1 += process_P_volt_to_idata_bytes;

        public void process_P_volt_to_idata_bytes(int index1)         {             if ((byte)index1 == (byte)SFR.P0)             {                 process_P_volt_to_idata_bytesDo((byte)SFR.P0, "P0");

            }             if ((byte)index1 == (byte)SFR.P1)             {                 process_P_volt_to_idata_bytesDo((byte)SFR.P1, "P1");

            }             if ((byte)index1 == (byte)SFR.P2)             {                 process_P_volt_to_idata_bytesDo((byte)SFR.P2, "P2");

            }             if ((byte)index1 == (byte)SFR.P3)             {                 process_P_volt_to_idata_bytesDo((byte)SFR.P3, "P3");

            }           

        }

===================================================================

如何调整WinForm界面ComboBox控件的高度

进击的路飞桑 2020-07-06 14:27:23  636  收藏 分类专栏: # C# 版权 打开ComboBox控件的属性页,调整字体即可改变其高度

=================================================================== 设备急停信号不要做成连续读plc是否急停标志位,而要做成2处:急停按钮控制plc急停,还有上位机软件里写1个w区的位来急停

=================================================================== 电流功率源的ict有些是发复位会强制断下电流一下,有些是如果没旁路则不会断一下,如果瞬间断一下源输出值可能异常!!

===================================================================

得做通讯使能:再上电稳定8秒后才开始上线通讯,不然没上电稳定就不断发通讯包,容易不稳定 ----

plc 别接地线,否则容易烧坏plc??

-- 232转485模块的铁外壳不要直接安装在设备外壳上固定,需要加绝缘板,否则容易导致TXD灯常亮等问题 ,其实不是模块问题,而是485转换模块的 232输入口的1号脚和5号脚这个gnd脚接反了,但是由于只用于发送而不接收,接反也能用, 但是不稳定,偶尔txd灯常亮。。。。。。。 ,所以对于只发送的通讯线路,出厂前要检查下232线序!!!

--

通信日志功能的重要性: 加了10工位的每个工位的通信日志功能后,可以看到有时清除断路器电量发包时返回心跳包的结果内容,说明心跳包和清除断路器电量发包冲突了,从而不稳定!!!!

===================================================================

NO.0000: 比如重发包超时时间为80ms,而断路器返回包的等待时间有100ms,则会在收到返回包前重发一个包,导致最终收到2个返回包, 而第2个返回包就干扰了后续发包的返回包,造成通讯纹乱: 所以: 所有包的重发包超时时间改大到1秒,原来只有120ms左右

,即加              if (isnowait == 0)//v1002:                                 {

                                    //防止重发包的返回包干扰下面的续包:                                     if (sleep_with_rt_ok(1 * 1000, gongwei_index, comm_index) == 1)                                     {                                         sended = 1;                                         break;

                                    }

                                }

        public int SendPortSP_try_more(string v20_sub_cmd_is_dl_or_68xieyi, int gongwei_index, int is_rec_senddata_str0_or_rec_senddata_len1, int comm_index, string cmd1, byte[] ombuffer, int wait_sec = -1, int isnowait = -1, int isPLC = -1, int is_stopmsg_err1 = 0, int is_nowait_for_liji_closeV = 0, int recv_mubiao_length = 0, byte headbyte = 0, string sub_cmd = "", float wait_sec_after_write=-1)         {     .........................

   if (wait_sec_after_write >= 0.01f)                                 {

                                    if (sleep_with_rt_ok(wait_sec_after_write * 1000, gongwei_index,comm_index) == 1)                                     {                                         sended = 1;                                         break;

                                    }

                                }

                                if (isnowait == 0)//v1002:                                 {

                                    //防止重发包的返回包干扰下面的续包:                                     if (sleep_with_rt_ok(1 * 1000, gongwei_index, comm_index) == 1)                                     {                                         sended = 1;                                         break;

                                    }

                                } =================================================================== NO1。 所有textBox和checkbox, radioButton等全部要用拼音尾缀来命名,不能用数字尾缀来命令,否则容易 弄错textBox,而导致隐藏的bug几个月

-----------------

有很多按钮的界面,可以把按钮的事件做成一个,然后switch (button.Name)一下,比分散写到各个事件函数里要方便:

        private void f1_h2004_Click(object sender, EventArgs e)         {             Button button = (Button) sender;             switch (button.Name)             {                 case "f1_h2004":                     this.x_Omron.写[0].value_D500[0x1b] = 1;                     this.x_Omron.写[0].cmd_D500[0x1b] = true;                     break;

                case "f1_h2005":

===================================================================

vs2010里如果复制某个界面的控件到新工程,那么所有输入框事件和combox控件的改变事件都要手工拷贝来,不然很可能改值后保存不住,

而引发写入参数不是改动的值,从而参数始终不变而改不了,误以为写成功了,比如跳闸阀值,这样有安全风险!!!!

=================================================================== 选择性序列化:

[Serializable] public class MyObject {    public int n1;    [NonSerialized] public int n2;    public String str; }

===================================================================

验证断路器等写入的参数是否正确写入时,缓存原始写入值的变量最好带绝对地址,否则按变量索引增量时容易出日后的兼容性问题:

        //v3.3:         public int get_val_by_writed_d_addr(int addr11, List<v1000_val_cls> writed_d)         {

            foreach (v1000_val_cls in1 in writed_d)             {                 if (in1.addr == addr11)                 {

                    return in1.val1;

                }

            }             return -1;

        }

===================================================================

            int binval = (int)(Math.Round(Val_to_jiaozhuan) * chengyi_100_or_1000);

如果Val_to_jiaozhuan为零点几,就会异常!!,要注意,所以改为int binval = (int)(Math.Round(Val_to_jiaozhuan* chengyi_100_or_1000) );

===================================================================

  启动主校准进程之类后,再次开始时,除了判断 是否校准中 变量外,还要判断这个主校准进程是否isalive和running

===================================================================

像jieti的断路器板子,校准时 增益点和偏移点的给定电压电流值必须为20%的比率关系,不然校不准!

===================================================================

像今闰的三相源读电压电流等返回1失败后,需要再重试2-4次!!!,不然不稳定

=================================================================== ict报警旁路打开,可能不是产品和夹具的问题,可能是铜排没有拧紧而接触不良,也可能上铜排和下铜排同时接触不良,都要拧紧才能解决

---

断路器计量型的产品不同系列可能脉冲常数不一样,导致脉冲误差检测老是50%误差之类

===================================================================

同一时刻同时2个电压源报警保护,很可能是源间回路有短路,比如换相开关和电流源的换相时的回路导致ab相间短路

,另外,如果电压源老过载保护或IGBT保护而断电,则可以串一个50欧到100欧左右的电阻,可以防止保护

=================================================================== 机械手取料时料框里放个复杂图案,机械手上装摄像头来模板识别这个图案,获得料框的xy偏移,也可以用于料分类的识别, 料框里用放料孔夹死料,来限位料,这样不用视觉也可以准确取料,

===================================================================

小220v继电器换为大的220V交流接触器,是否灵敏度降低?,从而自动在毛刺时不跳

=================================================================== 写串口等写函数不要存在2个以上的线程在同时写串口,即使是加了lock(obj) ,可以做成1个写thread,  然后这个 thread里接收其他线程的发串口命令,来一个一个发包,

这样可以防止比如心跳包的返回干扰其他包的返回,然后写thread里2次写间隔个20ms最好, ------- 最好做成执行完几步后进行一步校验等,比如执行完。。。。步后最后对比电压电流值是否校准通过,然后不通过时可以重试,这样即使哪步丢包或错误,也可以最终自动修正, 这样程序的稳定性和鲁棒性好点!!!

===================================================================

移植老项目到新项目里时,务必先烤出来一份,再复制,防止改乱老的

===================================================================

有时候断路器校准完不准,不是校准本身问题,还可能是电压电流可能是BCD码或解析异常,导致实际通讯过来的值不准!!

不要实时通讯监测产品上线否,而要再产品上电完成后等待5秒左右后再开始通讯,防止刚通电不稳定而乱写初始化sn等

===================================================================

UT1616串口服务器的串口接收超时设置 时间不能大于50ms?? :需要比 send...发包函数里的 wait返回信号量 的延时值要小!!

,不然容易一次收到2个包而导致校验不通过?

===================================================================

双倍误差原理,漏电一直校验不准:

不代入当前漏电流值: _Current_LD;,否则因为_Current_LD不是实时的,从而导致漏电纠正的双倍误差!,所以还不如用漏电流设定值DC_cp_power_Lou_A:

                    if (is_jiaozhun_UI1_or_Lou0_or_xiangwei2 == 0)                     {

                        U_innn = 0;                         I_innn = 0;

                        U_innn2 = 0;                         I_innn2 = 0;

                        U_innn3 = 0;                         I_innn3 = 0;

                        Lou_innn = DC_cp_power_Lou_A * 1000;//不代入 _Current_LD;,否则因为_Current_LD不是实时的,从而导致漏电纠正的双倍误差!

                    

-----------

不过以上也可能是 (byte)( (int)(Lou_innn)&0xff),(byte)(((int)(Lou_innn)>>8)&0xff) 里的漏电流float值转为int值,比如29.999 ma,会自动变为29ma,

而不是自动四舍五入而变为 30ma,从而漏电流精度有问题,而校不准

===================================================================

c#用委托类似函数指针,这样可以使2个类相互解耦,从而模块化,提高代码可阅读性

===================================================================

所有参数做成拼音变量名等,不要写死程数字,该抽象为函数的就新建立函数,这样:大改时可以批量搜索某个变量名来定位所有相关点而不会漏掉,从而防止bug

===================================================================   this.FormBorderStyle = FormBorderStyle.Fixed3D;//需要关闭按钮, 不然卡死时关不了!!!

===================================================================

    internal static class Program     {         [STAThread]         private static void Main()         {             bool flag;             Mutex mutex = new Mutex(true, "HXV001", out flag);             if (flag)             {                 mutex.ReleaseMutex();                 Application.EnableVisualStyles();                 Application.SetCompatibleTextRenderingDefault(false);                 Application.Run(new Form1());             }             else             {                 MessageBox.Show("只能运行一个程序!");             }         }     }

===================================================================

随机性的不稳定也可能是 参数最大值为65535,而设为900000等之类,导致参数实际为30左右,这样的阀值遇到随机性的电流时时而过,时而没过,从而随机异常!

  ===================================================================

去掉最左边的空列和禁止自动添加新行,禁止拖拉列宽行宽,禁止选中行等:

        public void add_col(DataGridView inn,string id,string name,int width)         {

            DataGridViewColumn column = new DataGridViewTextBoxColumn();             column.HeaderText = name;             column.Name = id;             column.Width = width;             column.SortMode = DataGridViewColumnSortMode.NotSortable;             //column.CellTemplate = dgvcell;//设置模板             inn.Columns.Add(column);

        }

        public void add_row(DataGridView inn,string first_name,int[] init_cols)         {

           int index1= inn.Rows.Add();

           inn.Rows[index1].Cells[0].Value = first_name;

           foreach (int closindex in init_cols)            {

               inn.Rows[index1].Cells[closindex+1].Style.BackColor = Color.Green;

           }

        }         public void init_datadgirdview_do1(DataGridView inn)         {

            inn.EnableHeadersVisualStyles = false;

            inn.RowHeadersVisible = false;//去掉最左边的空列

            inn.AllowUserToAddRows = false;

            inn.AllowUserToResizeColumns = false;//设置datagridview的列宽不可被用户手动拖拉             inn.AllowUserToResizeRows = false;

            inn.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

            //dataGridView1_tiaoza.EditMode==DataGridViewEditMode.EditOnEnter

            inn.CellBorderStyle = DataGridViewCellBorderStyle.Raised;//单元格无边框化

            inn.DefaultCellStyle.BackColor = this.dataGridView1_tiaoza.Parent.BackColor;

            inn.BorderStyle = BorderStyle.None;

            inn.BackgroundColor = this.dataGridView1_tiaoza.Parent.BackColor;

          

        }

        public void init_datadgirdview_yaoxin()         {

            init_datadgirdview_do1(dataGridView1_tiaoza);

            add_col(dataGridView1_tiaoza, "id", "跳闸", 100);             add_col(dataGridView1_tiaoza, "zong", "总线路", 68);

            add_col(dataGridView1_tiaoza, "a", "A相", 66);

            add_col(dataGridView1_tiaoza, "b", "B相", 66);

            add_col(dataGridView1_tiaoza, "c", "C相", 66);

            add_col(dataGridView1_tiaoza, "N", "零线", 66);

            add_row(dataGridView1_tiaoza, "微断死状态",new int[]{0});             add_row(dataGridView1_tiaoza, "过流保护", new int[] { 1,2,3 });             add_row(dataGridView1_tiaoza, "过载保护异常", new int[] { 1, 2, 3 });             add_row(dataGridView1_tiaoza, "过压保护", new int[] { 1, 2, 3 });             add_row(dataGridView1_tiaoza, "欠压保护", new int[] { 1, 2, 3 });             add_row(dataGridView1_tiaoza, "线路电弧", new int[] { 1, 2, 3 });             add_row(dataGridView1_tiaoza, "高温保护", new int[] { 1, 2, 3,4 });             add_row(dataGridView1_tiaoza, "漏电保护", new int[] { 0 });             add_row(dataGridView1_tiaoza, "三相不平衡", new int[] { 0 });             add_row(dataGridView1_tiaoza, "缺相保护", new int[] { 0 });

            init_datadgirdview_do1(dataGridView_gaojing);

            add_col(dataGridView_gaojing, "id", "告警", 100);             add_col(dataGridView_gaojing, "zong", "总线路", 68);

            add_col(dataGridView_gaojing, "a", "A相", 66);

            add_col(dataGridView_gaojing, "b", "B相", 66);

            add_col(dataGridView_gaojing, "c", "C相", 66);

            add_col(dataGridView_gaojing, "N", "零线", 66);

            add_row(dataGridView_gaojing, "过流保护", new int[] { 1, 2, 3 });             add_row(dataGridView_gaojing, "过载保护异常", new int[] { 1, 2, 3 });             add_row(dataGridView_gaojing, "过压保护", new int[] { 1, 2, 3 });             add_row(dataGridView_gaojing, "欠压保护", new int[] { 1, 2, 3 });             add_row(dataGridView_gaojing, "线路电弧", new int[] { 1, 2, 3 });             add_row(dataGridView_gaojing, "高温保护", new int[] { 1, 2, 3,4 });             add_row(dataGridView_gaojing, "漏电保护", new int[] { 0 });             add_row(dataGridView_gaojing, "三相不平衡", new int[] { 0 });             add_row(dataGridView_gaojing, "缺相保护", new int[] { 0 });

        }

        private void dataGridView1_tiaoza_SelectionChanged_1(object sender, EventArgs e)         {             dataGridView1_tiaoza.ClearSelection();         }

        private void dataGridView_gaojing_SelectionChanged(object sender, EventArgs e)         {             dataGridView_gaojing.ClearSelection();         }

        private void dataGridView_qita_SelectionChanged(object sender, EventArgs e)         {             dataGridView_qita.ClearSelection();         }

  ===================================================================

上层是个循环,所以这里不能用 return;,需要  continue:

                              if (client1_To == null)                                 {

                                    showmsg(ip1 + " toid not find!");

                                    myClientSocket.Send(Encoding.ASCII.GetBytes("toid not find!"));                                     continue;//上层是个循环,所以这里不能用 return;,需要  continue                                 }

=================================================================== 有重发机制的返回包时最好不只用if ( rttobj.recv_ok1b == 1) 之类,而用当前包的cur_cmd字符串经由hashtable来分开置 recv_ok1b,这样 可以防止上一个包的确认包影响当前包的recv_ok1b而漏包 , 或者用 if(recv_buf[2]==100&&cur_cmd="xintiaobao" )机制来判断,但这容易永不成立???

===================================================================

以下里的if ( rttobj.recv_ok1b != 1)  可以删掉,防止上一个包的确认包影响当前包的recv_ok1b而漏包!!!:

                        while (isrunning == 1 && max_retrycount <= maxccc)                         {

                            //if ( rttobj.recv_ok1b != 1)                                   {

                                rttobj.v16_buffer.Clear();//v90                                 rttobj.v40_cur_datastep = 0;//v90

                                if (rttobj.v20_is_UT6616 == 0)                                 {

                                    rttobj.v16_data_recv_timeout_enable = 1;//old                                     rttobj.v16_data_recv_timeout_ccc = DateTime.Now;//old

                                    rttobj.OP_s.SP.Write(ombuffer, 0, ombuffer.Length);                                 }                                 else                                 {

                                    Connect(rttobj.gongwei_index);                                     SendData(ombuffer, rttobj.gongwei_index);

                                }

                                if (wait_sec_after_write >= 1)                                 {

                                    if (sleep_with_rt_ok(wait_sec_after_write * 1000, gongwei_index) == 1)                                     {                                         sended = 1;                                         break;

                                    }

                                }

                            }

--------------------------

===================================================================

有时候返回包了但功能没执行到位,可能不是因为其本身,而且启动代码有问题,导致已经在工作的假象

=================================================================== 读参数到输入框前先清空输入框,防止本次读失败,而遗传上次的输入框值!!

===================================================================

发包函数里的发包状态清零语句前最好加 System.Threading.Thread.Sleep(3);,防止下一个包影响上一个包的发包代码后的if(recv_ok1b!=1.........:

        public int SendPortSP_try_more(string v20_sub_cmd_is_dl_or_68xieyi, int gongwei_index, int is_rec_senddata_str0_or_rec_senddata_len1, int comm_index, string cmd1, byte[] ombuffer, int wait_sec = -1, int isnowait = -1, int isPLC = -1, int is_stopmsg_err1 = 0, int is_nowait_for_liji_closeV = 0, int recv_mubiao_length

标签: 通电继电器吸合一秒再断开贴片电容2200uf35v怎样二极管可以当做绝缘体使用吗电容1000v80aemi滤波电路xy电容直角f头防水f射频连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台