|
#申请原创# 大家有没有为NSA2860压力传感器变送芯片资料少、协议复杂,不能解锁等问题而发愁? 本帖就参考NSA2860 Datasheet和NSA2860单颗校准系统软件,利用逻辑分析仪进行检测其通信协议,抽丝剥茧,分析其通信协议。 1、NSA2860这颗芯片介绍 它是一款高度集成的传感器信号调理与变送专用芯片,将完整的模拟信号链、数字校准和多种输出接口集成于单芯片。 三大核心功能: 采集:集成双 24 位 ADC、PGA 和恒流/压源,可高精度采集传感器(压力、RTD、热电偶等)和温度信号。 补偿:内置 MCU 和校准算法,支持对传感器进行二阶温漂和三阶非线性补偿,精度达 0.1%。 输出:提供 4~20mA、0~5/10V、PWM/PDM 等多种变送输出,并集成 16 位 DAC。 核心优势: 简化设计:集成 JFET 控制器,可直接从工业总线取电,支持两线制方案。 灵活配置:支持 OWI(单总线)、SPI、I2C 通信,特别是 OWI 协议,无需额外接线即可在输出线上完成配置和校准。 高集成度:大幅减少外围元件,降低成本与体积。 主要应用: 压力/温度变送器、工业过程控制传感器模块等。 2、通信接口和协议 NSA2860支持三种通信协议,其中OWI(单线接口)是其最具特色的专有协议,主要应用于两线制(4-20mA)变送器场景,无需额外通信线即可完成校准。 本帖就用的是OWI通信接口。 部分电路图如下 通过S1_CMD控制传感器通电,电源为DC24V,通过S1_DATA控制直流载波信号,给传感器发送数据,通过三个精密电阻并联采样输出电流变化,再经过放大(LM321)、比较(LM393)后通过三极管Q5电平转换后送到单片机的R1_DATA接口。 校准主要涉及到读写ID、初始化芯片、DAC校准、采集数据、烧录、EE锁定和解锁等操作。 下面分别介绍: 读ID: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 图中数据高电平760us为逻辑1,高电平252us为逻辑0 分析进入OWI模式:系统reset后有18.418ms的低电平,被识别为起始信号,然后发送0xB5A6C9进入OWI模式,其他协议解析如下。 写ID: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: 初始化: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: (数据太大,请参见附件) DAC校准: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: 数据采集: 分别采集4、12、20mA的数据,用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: (数据太大,请参见附件) 烧录: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: EE锁定: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: EE解锁: 用逻辑分析仪分别监控发送和接收端的电平,如图所示 协议解析如下: 3、软件设计 根据以上监测到的协议,编写NSA2860驱动程序,关键代码如下: u16 delay_start = 290, delay_stop = 840; u16 delay_long = 72, delay_shot = 220; void NSA_send_start(u8 NSA_num) //起始信号 { switch(NSA_num) { case 0: Send_data1 = 0; delay_us(delay_start); Send_data1 = 1; break; case 1: Send_data2 = 0; delay_us(delay_start); Send_data2 = 1; break; case 2: Send_data3 = 0; delay_us(delay_start); Send_data3 = 1; break; } } void NSA_send_stop(u8 NSA_num) //结束信号 { switch(NSA_num) { case 0: Send_data1 = 1; break; case 1: Send_data2 = 1; break; case 2: Send_data3 = 1; break; } delay_us(delay_stop); } void NSA_send_0(u8 NSA_num) //发送0 { switch(NSA_num) { case 0: Send_data1 = 1; delay_us(delay_long); Send_data1 = 0; delay_us(delay_shot); Send_data1 = 1; break; case 1: Send_data2 = 1; delay_us(delay_long); Send_data2 = 0; delay_us(delay_shot); Send_data2 = 1; break; case 2: Send_data3 = 1; delay_us(delay_long); Send_data3 = 0; delay_us(delay_shot); Send_data3 = 1; break; } } void NSA_send_1(u8 NSA_num) //发送1 { switch(NSA_num) { case 0: Send_data1 = 1; delay_us(delay_shot); Send_data1 = 0; delay_us(delay_long); Send_data1 = 1; break; case 1: Send_data2 = 1; delay_us(delay_shot); Send_data2 = 0; delay_us(delay_long); Send_data2 = 1; break; case 2: Send_data3 = 1; delay_us(delay_shot); Send_data3 = 0; delay_us(delay_long); Send_data3 = 1; break; } } u8 NSA_rec_real_data_sinal(u8 NSA_num, u8 send_num) { u8 data_check1 = 0, data_check2 = 0, i = 0; switch(NSA_num) { case 0: for(i = 0; i < send_num; i++) { data_check1 = (((exti2_rec_data >> 3) & 1) + ((exti2_rec_data >> 5) & 1) + ((exti2_rec_data >> 7) & 1) + ((exti2_rec_data >> 9) & 1)) % 2; data_check2 = (((exti2_rec_data >> 2) & 1) + ((exti2_rec_data >> 4) & 1) + ((exti2_rec_data >> 6) & 1) + ((exti2_rec_data >> 8) & 1)) % 2; if((((exti2_rec_data >> 1) & 1) == data_check1) && (((exti2_rec_data >> 0) & 1) == data_check2)) NSA_read_sinal[send_num - i - 1] = (u8)(exti2_rec_data >> 2); else return 0xFF; exti2_rec_data = exti2_rec_data >> 10; } break; case 1: for(i = 0; i < send_num; i++) { data_check1 = (((exti0_rec_data >> 3) & 1) + ((exti0_rec_data >> 5) & 1) + ((exti0_rec_data >> 7) & 1) + ((exti0_rec_data >> 9) & 1)) % 2; data_check2 = (((exti0_rec_data >> 2) & 1) + ((exti0_rec_data >> 4) & 1) + ((exti0_rec_data >> 6) & 1) + ((exti0_rec_data >> 8) & 1)) % 2; if((((exti0_rec_data >> 1) & 1) == data_check1) && (((exti0_rec_data >> 0) & 1) == data_check2)) NSA_read_sinal[send_num - i - 1] = (u8)(exti0_rec_data >> 2); else return 0xFF; exti0_rec_data = exti0_rec_data >> 10; } break; case 2: for(i = 0; i < send_num; i++) { data_check1 = (((exti1_rec_data >> 3) & 1) + ((exti1_rec_data >> 5) & 1) + ((exti1_rec_data >> 7) & 1) + ((exti1_rec_data >> 9) & 1)) % 2; data_check2 = (((exti1_rec_data >> 2) & 1) + ((exti1_rec_data >> 4) & 1) + ((exti1_rec_data >> 6) & 1) + ((exti1_rec_data >> 8) & 1)) % 2; if((((exti1_rec_data >> 1) & 1) == data_check1) && (((exti1_rec_data >> 0) & 1) == data_check2)) NSA_read_sinal[send_num - i - 1] = (u8)(exti1_rec_data >> 2); else return 0xFF; exti1_rec_data = exti1_rec_data >> 10; } break; } return 0; } u8 NSA_send_rec_data(u8 NSA_num, u8 add, u8 R1_W0, u8 len, u8* data) //发送接收数据,add地址,read_write读或写数据,len读写长度,data写数据 { s8 i = 0, j = 0; switch(NSA_num) { case 0: EXTI->IMR &= ~(EXTI_Line2); //关闭外部中断 exti2_rec_data = 0; break; case 1: EXTI->IMR &= ~(EXTI_Line0); //关闭外部中断 exti0_rec_data = 0; break; case 2: EXTI->IMR &= ~(EXTI_Line1); //关闭外部中断 exti1_rec_data = 0; break; } NSA_send_start(NSA_num); //上一个函数结束到这个需要842us for(i = 7; i >= 0; i--) //地址 { if((add >> i) & 0x01) NSA_send_1(NSA_num); else NSA_send_0(NSA_num); } if((len <= 4) && (len >= 1)) //长度 { len = len - 1; for(i = 1; i >= 0; i--) { if((len >> i) & 0x01) NSA_send_1(NSA_num); else NSA_send_0(NSA_num); } } else return 0xFD; if(R1_W0 == 0) //读写数据,0写1读 { NSA_send_0(NSA_num); for(j = 0; j <= len; j++) { for(i = 7; i >= 0; i--) //地址 { if((data[j] >> i) & 0x01) NSA_send_1(NSA_num); else NSA_send_0(NSA_num); } } } else { NSA_send_1(NSA_num); switch(NSA_num) { case 0: tim2_num_ins_2 = 0; EXTI->IMR |= EXTI_Line2; //开启外部中断 break; case 1: tim2_num_ins_0 = 0; EXTI->IMR |= EXTI_Line0; //开启外部中断 break; case 2: tim2_num_ins_1 = 0; EXTI->IMR |= EXTI_Line1; //开启外部中断 break; } } NSA_send_stop(NSA_num); switch(NSA_num) { case 0: flag_rec_end_2 = 0; if(R1_W0 == 1) { while(flag_rec_end_2 < 100) delay_us(10); delay_ms(2); return NSA_rec_real_data_sinal(NSA_num, len + 1); } else { while(flag_rec_end_2 < 100) delay_us(10); delay_ms(1); } break; case 1: flag_rec_end_0 = 0; if(R1_W0 == 1) { while(flag_rec_end_0 < 100) delay_us(10); delay_ms(2); return NSA_rec_real_data_sinal(NSA_num, len + 1); } else { while(flag_rec_end_0 < 100) delay_us(10); delay_ms(1); } break; case 2: flag_rec_end_1 = 0; if(R1_W0 == 1) { while(flag_rec_end_1 < 100) delay_us(10); delay_ms(2); return NSA_rec_real_data_sinal(NSA_num, len + 1); } else { while(flag_rec_end_1 < 100) delay_us(10); delay_ms(1); } break; } return 0; } void NSA_send_OWI(u8 NSA_num) //发送OWI命令0xB5A6C9 { s8 i = 0; u32 data_owi = 0xB5A6C9; NSA_send_start(NSA_num); for(i = 23; i >= 0; i--) //地址 { if((data_owi >> i) & 0x01) NSA_send_1(NSA_num); else NSA_send_0(NSA_num); } NSA_send_stop(NSA_num); } void NSA_reboot(u8 NSA_num) { switch(NSA_num) { case 0: Send_cmd1 = 0; delay_ms(18); Send_data1 = 0; delay_ms(192); //重启NSA2860 Send_cmd1 = 1; delay_ms(18); Send_data1 = 1; delay_ms(48); break; case 1: Send_cmd2 = 0; delay_ms(18); Send_data2 = 0; delay_ms(192); //重启NSA2860 Send_cmd2 = 1; delay_ms(18); Send_data2 = 1; delay_ms(48); break; case 2: Send_cmd3 = 0; delay_ms(18); Send_data3 = 0; delay_ms(192); //重启NSA2860 Send_cmd3 = 1; delay_ms(18); Send_data3 = 1; delay_ms(48); break; } } 4、界面设计 软件界面设计如下 实际应用界面如下 通过激活通信、DAC校准、数据采集、计算烧录后,就完成了压力传感器的校准工作,校准完还可以对当前压力和压力源进行对比,如图所示。 如需具体实现,可参考本人分享的源码(NSA2860的压力传感器校准工装和算法)https://dl.21ic.com/download/ic-867282.html |