分类目录归档:LINUX C & ARM & C51

【BYSSJ】开源 破解小牛电动车电池BMS(附源码) N1 N1S M1 U1 均可用

开篇: 之前发了一个贴子 破解小牛电动车电池BMS http://bbs.mydigit.cn/read.php?tid=2497489
这贴很水,只是简单了说一下破解的过程,但就这么一点点的贡献就得到了广大网友的支持。
这让我感到深深的惭愧。。。。让我久久不能入睡。。。。。。。。。。。。。`~~~~~~~~~~~ZZZ。。。
所以我考虑把代码发出来,造福大家,但又考虑到我自己的饭碗问题。
所以这次发一个阉割的版本。这次是干货,内容包括PCB源文件,与 IAR 源代码。
阉割的部分就是电容锁定在100%。其它的部分正常。
全系列车型可用,电路是V1.1版本的,最新的是V3.31,目前还没发布汗一个
电路部分是包括电压识别的,我只是在程序上阉割了,有能力的网友可以自己加上去这个功能

需要的工具:
STLINK 一个 刷程序用的
电路板:V1.1是之前剩下的,还有6个,有需要的可以问我(有图你都找不到我,那说明你应该是搞不定)
AD,IAR

哎,算了 TB 搜 【BYSSJ】可以找到我.
下图是正事。镇楼图

干货下载(电路图+IAR 源代码):NIU_BMS_V1.1_20180810_GNU

 

 

 

 

NIU_BMS_V1.11

STM8的ADC的五种工作模式

STM8的ADC的五种工作模式

STM8的ADC是10位的逐次比较型模拟数字转换器,多达16个多功能的输入通道。拥有5种转换模式,转换结束可产生中断。

STM8 ADC的初始化顺序如下:

1、AD输入通道对应的IO设置为上拉输入;

2、配置AD参数,如:预分频系数、是否使用外部触发转换、是否使用施密特触发器、是否使用缓存以及是否使用扫描模式等;

3、开启ADC;

4、开启转换;

注意!开启ADC和开启转换实际上都是置位ADON。

然后就可以通过ADC_DR寄存器读取转换后的值。

l单次模式:

在单次转换模式中,ADC仅在由ADC_CSR寄存器的CH[3:0]选定的通道上完成一次转换。该模式是在当CONT位为0时通过置位ADC_CR1寄存器的ADON位来启动的。

一旦转换完成,转换后的数据存储在ADC_DR寄存器中,EOC(转换结束)标志被置EOCIE 被置位将产生一个中断。

注意!初始化的时候只能选择一个通道。转换多个通道只能通过反复重新初始化或扫描模式!

示例程序:

void adc_init(void)

{

GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_NO_IT);//AIN4 IO设置为上拉输入

ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2);//预分频2

ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM,DISABLE);//不使用外部触发

ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4,DISABLE);

//禁止AIN2 AIN4的施密特触发器,降低IO静态功耗

//PD5,PD6上的通道如果施密特方式禁用会导致串口无法收发数据!

ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,//单次转换

ADC1_CHANNEL_4,//只能选择一个通道!

ADC1_ALIGN_RIGHT);//右对齐

ADC1_Cmd(ENABLE);//开启ADC

}

void main( void )

{

u16value=0;

adc_init();

while(1)

{

ADC1_StartConversion();//开启一次转换一次

while(!ADC1_GetFlagStatus(ADC1_FLAG_EOC));//等待转换完成

ADC1_ClearFlag(ADC1_FLAG_EOC);//软件清除

value=(u16)ADC1_GetConversionValue();//从ADC_DR中读取ADC值

}

}

l连续模式与带缓存的连续模式:

在连换模式中,ADC在完成一次转换后就立刻开始下一次的转换。当CONT位被置位时即将ADC设为连续模式,该模式是通过置位 ADC_CR1寄存器的 ADON 位来启动的。

如果缓冲功能没有被使能(ADC_CR3寄存器的DBUF位=0),那么转换结果数据保存在ADC_DR寄存器中同时 EOC 标志被置位。如果EOCIE 位已被置位时将产生一次中断。然后开始下一次转换。

如果缓存功能被使能(DBUF=1),那么某个选定通道上的8个或者10个连续的转换结果会填满数据缓存(此时填满的是同一个通道的数据!!扫描模式时才是不同通道的数据!),当缓存被填满时,EOC(转换结束)标志被置位,如果EOCIE位已被置位,则会产生一个中断,然后一个新的转换自动开始。如果某个数据缓存寄存器在被读走之前被覆盖,OVR标志将置1。

如果要停止连续转换,可以复位清零CONT位来停止转换或者复位清零ADON位来关闭ADC的电源。

示例程序(不带缓存):

void adc_init(void)

{

GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_NO_IT);//AIN4 IO设置为上拉输入

ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2);//预分频2

ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM,DISABLE);//不使用外部触发

ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4,DISABLE);

//禁止AIN2 AIN4的施密特触发器,降低IO静态功耗

//PD5,PD6上的通道如果施密特方式禁用会导致串口无法收发数据!

ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS, //连续转换

ADC1_CHANNEL_4,//只能选择一个通道!

ADC1_ALIGN_RIGHT);//右对齐

ADC1_Cmd(ENABLE);//开启ADC

ADC1_StartConversion();//开启连续转换

}

void main( void )

{

u16value=0;

adc_init();

while(1)

{

while(!ADC1_GetFlagStatus(ADC1_FLAG_EOC));//等待转换完成

ADC1_ClearFlag(ADC1_FLAG_EOC);//软件清除

value=(u16)ADC1_GetConversionValue();//从ADC_DR中读取ADC值

}

}

示例程序(带缓存):

void adc_init(void)

{

GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_NO_IT);//AIN4 IO设置为上拉输入

ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2);//预分频2

ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM,DISABLE);//不使用外部触发

ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4,DISABLE);

//禁止AIN2 AIN4的施密特触发器,降低IO静态功耗

//PD5,PD6上的通道如果施密特方式禁用会导致串口无法收发数据!

ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS, //连续转换

ADC1_CHANNEL_4,//只能选择一个通道!

ADC1_ALIGN_RIGHT);//右对齐

ADC1_Cmd(ENABLE);//开启ADC

ADC1_StartConversion();//开启连续转换

ADC1_DataBufferCmd(ENABLE);//开启缓存

}

void main( void )

{

u16value=0;

adc_init();

while(1)

{

while(!ADC1_GetFlagStatus(ADC1_FLAG_EOC));//等待转换完成

ADC1_ClearFlag(ADC1_FLAG_EOC);//软件清除

value=0;

for(u8 i=0;i<10;i++)//

{

value+=ADC1_GetBufferValue(i);//将10个缓存中的值求和

}

value=value/10;//求出ADC的平均值

}

}

注意,只有在连续转换模式下ADC_DB寄存器才能称之为缓存,此时存储的是同一个通道多次转换的值。在单次扫描和连续扫描模式下该寄存器被用来存放不同通道的转换值。

l单次扫描模式:

该模式是用来转换从AIN0到AINn之间的一连串模拟通道,‘n’是在 ADC_CSR寄存器的CH[3:0]位中指定的通道编号(即CH[3:0]里配置第n个通道,就从通道0顺序递增逐个通道进行转换,直到第n个通道结束。例如,CH[3:0]里配置为AIN4,则对AIN0、AIN1、AIN2、AIN3、AIN4进行转换,其他通道不转换)。在扫描转换的过程中,序号 CH[3:0]位的值是被硬件自动更新的,它总保存当前正在被转换的通道编号。

单次转换模式可以在在SCAN 位被置位且CONT 位以被清零时通过置位 ADON 位来启动。

注意:当使用扫描模式时,不可以将AIN0到AINn之间通道对应的I/O口设为输出状态,因为ADC的多路选择器已经将这些I/O口的输出模块禁用了。

对于单次扫描模式,转换是从AIN0通道开始的,而且结果数据被存储在数据缓冲寄存器ADC_DBxR 中(例如,CH[3:0]里配置为AIN4,则ADC_DB0R存放AIN0的转换结果,ADC_DB1R存放AIN1的转换结果,以此类推。 ),当最后一个通道(通道‘n’)被转换完成后,EOC(转换结束)标志被置位,当EOCIE 位已被置位时将产生一个中断。

可以从缓冲寄存器中读取各个通道的转换结果值。如果某个数据缓存寄存器在被读走之前被覆盖,OVR标志将置1。

在转换序列正在进行过程中不要清零SCAN位;单次扫描模式可通过清零ADON位来立即停止。为了开启一次新SCAN扫描转换,可以通过对ADC_CR1寄存器的EOC位清零和ADON位置位来实现。

示例程序:

void adc_init(void)

{

GPIO_Init(GPIOC,GPIO_PIN_4,GPIO_MODE_IN_PU_NO_IT);//AIN2IO设置为上拉输入

GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_NO_IT);//AIN4 IO设置为上拉输入

ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2);//预分频2

ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM,DISABLE);//不使用外部触发

ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4,DISABLE);

//禁止AIN2 AIN4的施密特触发器,降低IO静态功耗

//PD5,PD6上的通道如果施密特方式禁用会导致串口无法收发数据!

ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,//单次转换

ADC1_CHANNEL_4,//配置通道号最大的那个

ADC1_ALIGN_RIGHT);//右对齐

ADC1_Cmd(ENABLE);//开启ADC

ADC1_ScanModeCmd(ENABLE);//开启扫描模式

}

void main( void )

{

u16value1=0;

u16value2=0;

adc_init();

while(1)

{

ADC1_StartConversion();//开启一次转换

while(!ADC1_GetFlagStatus(ADC1_FLAG_EOC));//等待转换完成

ADC1_ClearFlag(ADC1_FLAG_EOC);//软件清除

value1=(u16)ADC1_GetBufferValue(ADC1_SCHMITTTRIG_CHANNEL2)//读取AIN2的值

value2=(u16)ADC1_GetBufferValue(ADC1_SCHMITTTRIG_CHANNEL4)//读取AIN4的值

}

}

l连续扫描模式:

该模式和单次扫描模式相近,只是每一次在最后通道转换完成时,一次新的从通道0到通道n扫

描转换会自动开始。如果某个数据缓存寄存器在被读走之前被覆盖,OVR标志将置1。连续扫描模式是在当SCAN位和CONT位已被置时,通过置位ADON位来启动的。在转换序列正在进行过程中不要清零SCAN位。

连续扫描模式可以通过清零ADON位来立即停止。另外一种选择就是当转换过程中清除CONT位那么转换会在下一次的最后一个通道转换完成时停止。

注意:在扫描模式(连续扫描模式)中,不要使用位操作指令(BRES)去清除EOC标志位,这是因为该指令是对整个ADC_CSR寄存器的一个读-修改-写操作。从CH[3:0]寄存器中读取当前的通道编号和写回该寄存器,将会改变扫描系列的最后通道编号。在连续扫描模式中正确的清除EOC标志位的方法是 个RAM变量中载入一个字节到ADC_CSR寄存器,这样来清除EOC标志位同时还重新载入扫描系列新的最后通道编号。

笔者实验发现,位操作指令只在连续扫描模式中会清除CH[3:0]寄存器中的值,但并不影响其他值。因此将ADC_CSR中的值读出,再将CH[3:0]中原来通道号加入进去,最后重新写入ADC_CSR中即可。写法如下:

ADC1->CSR = (uint8_t)(ADC1->CSR &(~ADC1_FLAG_EOC)|ADC1_CHANNEL_n);

注:ADC1_CHANNEL_n表示扫描到那个通道结束。

示例程序:

void adc_init(void)

{

GPIO_Init(GPIOC,GPIO_PIN_4,GPIO_MODE_IN_PU_NO_IT);//AIN2IO设置为上拉输入

GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_NO_IT);//AIN4 IO设置为上拉输入

ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2);//预分频2

ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM,DISABLE);//不使用外部触发

ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4,DISABLE);

//禁止AIN2 AIN4的施密特触发器,降低IO静态功耗

//PD5,PD6上的通道如果施密特方式禁用会导致串口无法收发数据!

ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS, //连续转换

ADC1_CHANNEL_4,//配置通道号最大的那个

ADC1_ALIGN_RIGHT);//右对齐

ADC1_Cmd(ENABLE);//开启ADC

ADC1_ScanModeCmd(ENABLE);//开启扫描模式

ADC1_StartConversion();//开启转换

}

void main( void )

{

u16value1=0;

u16value2=0;

adc_init();

while(1)

{

while(!ADC1_GetFlagStatus(ADC1_FLAG_EOC));//等待转换完成

ADC1->CSR = (uint8_t)(ADC1->CSR &(~ADC1_FLAG_EOC)|ADC1_CHANNEL_4);//软件清除

value1=(u16)ADC1_GetBufferValue(ADC1_SCHMITTTRIG_CHANNEL2)//读取AIN2的值

value2=(u16)ADC1_GetBufferValue(ADC1_SCHMITTTRIG_CHANNEL4)//读取AIN4的值

}

}

至此,STM8的ADC的5种工作模式全部介绍完毕。总结一下学习经验就是仔细对照芯片手册编写程序,然后进行仿真调试,观察寄存器中的值的变化,从中领悟手册中的意思。

利用NETLINK检测USB热插拔的C语言实现

做嵌入式开发,尤其在网关、路由器或者其他支持USB设备的终端上,为了提高用户体验,我们常常需要支持自动识别并挂载USB设备功能。某些应用程序,在使用USB设备的过程中,也希望能够侦测到USB断开事件,不至于某些工作因为USB已经不存在而白做。在Linux下,我们主要有两种办法检测USB热插拔。
第一种便是定时检查/proc/scsi/scsi文件,该文件内会按照标准格式保存着当前设备内挂载的存储介质基本信息,如果在PC端,除了硬盘(ATA)、光驱(CD-ROM)外,就是USB设备(Direct-Access)了,轮询该scsi文件,检查文件内是否新增或减少数据便可实现自动侦测USB热插拔的效果。但是这种方法对于热插拔(hotplug)设备,如U盘,效果就没那么理想了,因为我们不知道设备什么时候插上,又是什么时候被拔掉了,只能验证当前是否已经插上或者已经拔除的事实。于是便有了另一种办法,我们采用一种特殊类的的文件描述符(套结字)专门用于Linux内核跟用户空间之间的异步通信,这种技术通常被成为NETLINK。
由于NETLINK是linux内置功能,所以使用起来很简单:创建一个AF_NETLINK协议族下NETLINK_KOBJECT_UEVENT类型的特殊文件描述符(套结字)CppLive,然后利用setsocketopt允许该文件描述符(套结字)复用其他端口,再利用band函数将自身进程绑定到特殊文件描述符(套结字)CppLive,最后利用select在while循环内监听CppLive是否可读,如果可读则调用recv接收Linux系统内核传递过来的数据并打印出来,这些输出便是USB热插拔信息。当然你也可以个性化地处理来自内核的热插拔信息,让程序变得更加智能以及人性化。

利用NETLINK检测USB热插拔的C语言实现代码如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <sys/socket.h>
  6. #include <linux/netlink.h>
  7. #define UEVENT_BUFFER_SIZE 2048
  8. int main(void)
  9. {
  10.     struct sockaddr_nl client;
  11.     struct timeval tv;
  12.     int CppLive, rcvlen, ret;
  13.     fd_set fds;
  14.     int buffersize = 1024;
  15.     CppLive = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
  16.     memset(&client, 0, sizeof(client));
  17.     client.nl_family = AF_NETLINK;
  18.     client.nl_pid = getpid();
  19.     client.nl_groups = 1; /* receive broadcast message*/
  20.     setsockopt(CppLive, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
  21.     bind(CppLive, (struct sockaddr*)&client, sizeof(client));
  22.     while (1) {
  23.         char buf[UEVENT_BUFFER_SIZE] = { 0 };
  24.         FD_ZERO(&fds);
  25.         FD_SET(CppLive, &fds);
  26.         tv.tv_sec = 0;
  27.         tv.tv_usec = 100 * 1000;
  28.         ret = select(CppLive + 1, &fds, NULL, NULL, &tv);
  29.         if(ret < 0)
  30.             continue;
  31.         if(!(ret > 0 && FD_ISSET(CppLive, &fds)))
  32.             continue;
  33.         /* receive data */
  34.         rcvlen = recv(CppLive, &buf, sizeof(buf), 0);
  35.         if (rcvlen > 0) {
  36.             printf(“%s\n”, buf);
  37.             /*You can do something here to make the program more perfect!!!*/
  38.         }
  39.     }
  40.     close(CppLive);
  41.     return 0;
  42. }

运行程序,测试U盘插入/拔除,输出如下:

  1. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1
  2. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0
  3. add@/module/usb_storage
  4. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6
  5. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6
  6. add@/bus/usb/drivers/usb-storage
  7. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0
  8. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
  9. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0
  10. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0
  11. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2
  12. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0
  13. change@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
  14. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb
  15. add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4
  16. add@/devices/virtual/bdi/8:16
  17. add@/module/fat
  18. add@/kernel/slab/fat_cache
  19. add@/kernel/slab/fat_inode_cache
  20. add@/module/vfat
  21. add@/module/nls_cp437
  22. add@/module/nls_iso8859_1
  23. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0
  24. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2
  25. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0
  26. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0
  27. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4
  28. remove@/devices/virtual/bdi/8:16
  29. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb
  30. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0
  31. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6
  32. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6
  33. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0
  34. remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1
  35. remove@/host6/target6:0:0

OpenWRT开发之——目录分析与make过程

1.目录介绍

有几个重要目录:package, target, build_dir, staging_dir, bin, dl, …

—include 目录是存放 *.mk 文件。这里的文件上是在Makefile里被include的

—build_dir/host 目录是建立工具链时的临时目录

—build_dir/toolchain-<arch>* 对应硬件的工具链的目录

—staging_dir/toolchain-<arch>*  是工具链的安装位置

—target/linux/<platform> 目录里面是各个平台(arch)的相关代码

—target/linux/<platform>/config-3.10 文件就是配置文件了

—dl 目录是’download’的缩写, 在 编译前期,需要从网络下载的数据包都会放在这个目录下,这些软件包的一个特点就是,会自动安装在所编译的固件中,也就是我们make menuconfig的时候,为固件配置的一些软件包。如果我们需要更改这些源码包,只需要将更改好的源码包打包成相同的名字放在这个目录下,然后开始编 译即可。编译时,会将软件包解压到build_dir目录下。

—build_dir/ 目录下进行解压,编译和打补丁等。

—package/ 目录里面包含了我们在配置文件里设定的所有编译好的软件包。默认情况下,会有默认选择的软件包。

在openwrt中ipk就是一切, 我们可以使用:

$ ./scripts/feeds update #来对软件包进行更新.
$ ./scripts/feeds search nmap #查找软件包'nmap'
Search results in feed ’packages’: 
nmap       Network exploration and/or security auditing utility
$ ./scripts/feeds install nmap #安装'nmap'这个软件

—feeds/packages 为执行./scripts/feeds install 之后的package。

—bin 目录下生成了很多bin文件,根据不同的平台来区分。

—bin/<platform>/package 目录里面有很多ipk后缀的文件,都是package目录下的源码在build_dir目录下编译后的生成的结果。

注:以上摘自:[openwrt框架分析]

2.包的make过程

比如:lua包,mips架构。

make步骤:

  1. 在 make 时,make 读取到 package/utils/lua/Makefile 文件内容。
  2. 如果git或svn源,那么就会在 tmp/dl/ 目录下将源代码 clone 下来。然后,将 clone 下来的源码删除 .git 或 .svn 目录删除,然后压缩成 lua-1.5.1.tar.gz 文件,并复制到 dl/ 目录下。
  3. 在编译前段,将 dl/ 目录下的 lua-1.5.1.tar.gz 文件解压到 build_dir/target-mips_<board>/ 目录下。
  4. 进入 build_dir/target-mips_<board>/lua-1.5.1/
  5. ./configure,make,make install。
  6. make install 会将生成的二进制文件安装到 build_dir/target-mips_<board>/lua-1.5.1/ipkg-ar71xx/ 目录下。
  7. 最后将 build_dir/target-mips_<board>/lua-1.5.1/ipkg-ar71xx/ 打成包成lua-5.1.5-1_ar71xx.ipk,并复制到 bin/ar71xx/packages/base/ 。出处:https://my.oschina.net/hevakelcj/blog/417402

编译ESP8266固件

一、编译环境配置

我们先安装编译需要的软件包
sudo apt-get install git autoconf build-essential gperf bison flex texinfo libtool libncurses5-dev wget gawk libc6-dev-amd64 python-serial libexpat-dev

export PATH=”/opt/xtensa-lx106-elf/bin/:$PATH”

报错:

/opt/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.2/include/sys/fcntl.h:31:34: fatal error: xtensa/simcall-fcntl.h: No such file or directory
#include <xtensa/simcall-fcntl.h>

cp -Rp ~/Share/ESP8266_RTOS_SDK/extra_include/xtensa ./

已知曲线上的点 求函数解析式

已知道曲线上的4个X及其对应的Y,怎么求y=f(x)的函数解析式。或者说函数原型吧
多谢了
x=1.2 y=3600 。。。。。。f(1.2)=3600
x=1.5 y=60 。。。。。。。f(1.5)=60
x=6 y=8。。。。。。。。。f(6)=8
x=9 y=0.2。。。。。。。。f(9)=0.2
其实这样的题目,最简单的方法就是用待定系数法来求,这有两种情况:
1、你的坐标平面上只有这4个点,且知道其坐标;
2、你的坐标平面上除了这4个点外,还有其他的点,只不过除了这4个点外,其他点的坐标未知。

对于第一种情况,最简单的方法就是多项式拟合法,有n个点,就拟合一个n-1次的多项式
比如你给的条件,就应该拟合曲线y=ax^3+bx^2+cx+d,这样,知道了4个点,可得4个方程,4个未知数,这个函数可以唯一确定下来。
我用计算机算了一下,得到了一个三次方程y = -315x^3 + 5194x^2 – 24096x + 25580,计算结果给出来的系数小数位数太少了,x取较小值的时候还比较靠谱,X比较大的时候,比如反算X=6和9的时候,丢掉的小数位数乘以6和9的三次方的值比较大了,但都被舍去了,因此,反算6的时候结果变成了-52,反算9的时候更大了。

对于第二种情况,用上面的方法计算出来的多项式不一定能够通过其他的点,这种情况下,你就只能采用离散数据的处理方法了,此时你也可以用多项式来拟合,这个多项式甚至可以是直线,只不过用不同的多项式时的统计偏差有大有小罢了,要想使求得的曲线通过所有的点,必须满足拟合曲线的最高阶次是数据点数量减以一。只有这样得到的方程组才有唯一解。