调整驱动

This commit is contained in:
许晟昊 2024-12-31 17:04:20 +08:00
parent e4c3e59332
commit 005cc792a8
939 changed files with 242358 additions and 2112 deletions

View File

@ -120,7 +120,8 @@
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
<Key>DLGUARM</Key> <Key>DLGUARM</Key>
</SetRegEntry> <Name>
</Name> </SetRegEntry>
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
<Key>JL2CM3</Key> <Key>JL2CM3</Key>
@ -179,6 +180,16 @@
<WinNumber>1</WinNumber> <WinNumber>1</WinNumber>
<ItemText>board,0x0A</ItemText> <ItemText>board,0x0A</ItemText>
</Ww> </Ww>
<Ww>
<count>4</count>
<WinNumber>1</WinNumber>
<ItemText>0x000020CF,0x0A</ItemText>
</Ww>
<Ww>
<count>5</count>
<WinNumber>1</WinNumber>
<ItemText>0x0063,0x0A</ItemText>
</Ww>
</WatchWindow1> </WatchWindow1>
<MemoryWindow1> <MemoryWindow1>
<Mm> <Mm>
@ -230,6 +241,12 @@
<pszMrulep></pszMrulep> <pszMrulep></pszMrulep>
<pSingCmdsp></pSingCmdsp> <pSingCmdsp></pSingCmdsp>
<pMultCmdsp></pMultCmdsp> <pMultCmdsp></pMultCmdsp>
<SystemViewers>
<Entry>
<Name>System Viewer\TIM6</Name>
<WinId>35905</WinId>
</Entry>
</SystemViewers>
<DebugDescription> <DebugDescription>
<Enable>1</Enable> <Enable>1</Enable>
<EnableFlashSeq>1</EnableFlashSeq> <EnableFlashSeq>1</EnableFlashSeq>
@ -493,7 +510,7 @@
</Group> </Group>
<Group> <Group>
<GroupName>User/lib</GroupName> <GroupName>User/system</GroupName>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel> <cbSel>0</cbSel>
@ -505,8 +522,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\aes.c</PathWithFileName> <PathWithFileName>..\User\system\btn.c</PathWithFileName>
<FilenameWithoutPath>aes.c</FilenameWithoutPath> <FilenameWithoutPath>btn.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -517,8 +534,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\clist.c</PathWithFileName> <PathWithFileName>..\User\system\delay.c</PathWithFileName>
<FilenameWithoutPath>clist.c</FilenameWithoutPath> <FilenameWithoutPath>delay.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -529,139 +546,139 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\cmac.c</PathWithFileName> <PathWithFileName>..\User\system\sys.c</PathWithFileName>
<FilenameWithoutPath>cmac.c</FilenameWithoutPath> <FilenameWithoutPath>sys.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\cmd.c</PathWithFileName>
<FilenameWithoutPath>cmd.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>22</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\data_analysis.c</PathWithFileName>
<FilenameWithoutPath>data_analysis.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>23</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\debug.c</PathWithFileName>
<FilenameWithoutPath>debug.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>24</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\filter.c</PathWithFileName>
<FilenameWithoutPath>filter.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>25</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\lib.c</PathWithFileName>
<FilenameWithoutPath>lib.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\malloc.c</PathWithFileName>
<FilenameWithoutPath>malloc.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>27</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\mlist.c</PathWithFileName>
<FilenameWithoutPath>mlist.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>28</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\pbuf.c</PathWithFileName>
<FilenameWithoutPath>pbuf.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>29</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\src\sqqueue.c</PathWithFileName>
<FilenameWithoutPath>sqqueue.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>30</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\lib\flow\flow_core.c</PathWithFileName>
<FilenameWithoutPath>flow_core.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
</Group> </Group>
<Group> <Group>
<GroupName>User/system</GroupName> <GroupName>User/lib</GroupName>
<tvExp>1</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel> <cbSel>0</cbSel>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\aes.c</PathWithFileName>
<FilenameWithoutPath>aes.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>22</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\clist.c</PathWithFileName>
<FilenameWithoutPath>clist.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>23</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\cmac.c</PathWithFileName>
<FilenameWithoutPath>cmac.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>24</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\cmd.c</PathWithFileName>
<FilenameWithoutPath>cmd.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>25</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\data_analysis.c</PathWithFileName>
<FilenameWithoutPath>data_analysis.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\debug.c</PathWithFileName>
<FilenameWithoutPath>debug.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>27</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\filter.c</PathWithFileName>
<FilenameWithoutPath>filter.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>28</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\lib.c</PathWithFileName>
<FilenameWithoutPath>lib.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>29</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\malloc.c</PathWithFileName>
<FilenameWithoutPath>malloc.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>30</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\src\mlist.c</PathWithFileName>
<FilenameWithoutPath>mlist.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File> <File>
<GroupNumber>8</GroupNumber> <GroupNumber>8</GroupNumber>
<FileNumber>31</FileNumber> <FileNumber>31</FileNumber>
@ -669,8 +686,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\system\src\btn.c</PathWithFileName> <PathWithFileName>..\User\system\lib\src\pbuf.c</PathWithFileName>
<FilenameWithoutPath>btn.c</FilenameWithoutPath> <FilenameWithoutPath>pbuf.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -681,8 +698,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\system\src\delay.c</PathWithFileName> <PathWithFileName>..\User\system\lib\src\sqqueue.c</PathWithFileName>
<FilenameWithoutPath>delay.c</FilenameWithoutPath> <FilenameWithoutPath>sqqueue.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -693,8 +710,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\system\src\sys.c</PathWithFileName> <PathWithFileName>..\User\system\lib\src\storage.c</PathWithFileName>
<FilenameWithoutPath>sys.c</FilenameWithoutPath> <FilenameWithoutPath>storage.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -705,8 +722,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\adcs.c</PathWithFileName> <PathWithFileName>..\User\system\lib\src\wl_flash.c</PathWithFileName>
<FilenameWithoutPath>adcs.c</FilenameWithoutPath> <FilenameWithoutPath>wl_flash.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -717,14 +734,46 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\system\lib\flow\flow_core.c</PathWithFileName>
<FilenameWithoutPath>flow_core.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group>
<Group>
<GroupName>User/system/bsp</GroupName>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>9</GroupNumber>
<FileNumber>36</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\adcs.c</PathWithFileName>
<FilenameWithoutPath>adcs.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>9</GroupNumber>
<FileNumber>37</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\bsp.c</PathWithFileName> <PathWithFileName>..\User\system\bsp\bsp.c</PathWithFileName>
<FilenameWithoutPath>bsp.c</FilenameWithoutPath> <FilenameWithoutPath>bsp.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File> <File>
<GroupNumber>8</GroupNumber> <GroupNumber>9</GroupNumber>
<FileNumber>36</FileNumber> <FileNumber>38</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -735,77 +784,17 @@
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File> <File>
<GroupNumber>8</GroupNumber> <GroupNumber>9</GroupNumber>
<FileNumber>37</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\i2cs.c</PathWithFileName>
<FilenameWithoutPath>i2cs.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>38</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\iwdgs.c</PathWithFileName>
<FilenameWithoutPath>iwdgs.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>39</FileNumber> <FileNumber>39</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\pwms.c</PathWithFileName>
<FilenameWithoutPath>pwms.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>40</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\spis.c</PathWithFileName>
<FilenameWithoutPath>spis.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>41</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\tims.c</PathWithFileName> <PathWithFileName>..\User\system\bsp\tims.c</PathWithFileName>
<FilenameWithoutPath>tims.c</FilenameWithoutPath> <FilenameWithoutPath>tims.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File>
<GroupNumber>8</GroupNumber>
<FileNumber>42</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\User\system\bsp\uarts.c</PathWithFileName>
<FilenameWithoutPath>uarts.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group> </Group>
<Group> <Group>

View File

@ -54,7 +54,7 @@
<CreateLib>0</CreateLib> <CreateLib>0</CreateLib>
<CreateHexFile>1</CreateHexFile> <CreateHexFile>1</CreateHexFile>
<DebugInformation>1</DebugInformation> <DebugInformation>1</DebugInformation>
<BrowseInformation>1</BrowseInformation> <BrowseInformation>0</BrowseInformation>
<ListingPath></ListingPath> <ListingPath></ListingPath>
<HexFormatSelection>1</HexFormatSelection> <HexFormatSelection>1</HexFormatSelection>
<Merge32K>0</Merge32K> <Merge32K>0</Merge32K>
@ -339,7 +339,7 @@
<MiscControls></MiscControls> <MiscControls></MiscControls>
<Define>STM32,USE_FULL_LL_DRIVER,HSE_VALUE=8000000,HSE_STARTUP_TIMEOUT=100,LSE_STARTUP_TIMEOUT=5000,LSE_VALUE=32768,EXTERNAL_CLOCK_VALUE=12288000,HSI_VALUE=16000000,LSI_VALUE=32000,VDD_VALUE=3300,PREFETCH_ENABLE=1,INSTRUCTION_CACHE_ENABLE=1,DATA_CACHE_ENABLE=1,STM32F407xx</Define> <Define>STM32,USE_FULL_LL_DRIVER,HSE_VALUE=8000000,HSE_STARTUP_TIMEOUT=100,LSE_STARTUP_TIMEOUT=5000,LSE_VALUE=32768,EXTERNAL_CLOCK_VALUE=12288000,HSI_VALUE=16000000,LSI_VALUE=32000,VDD_VALUE=3300,PREFETCH_ENABLE=1,INSTRUCTION_CACHE_ENABLE=1,DATA_CACHE_ENABLE=1,STM32F407xx</Define>
<Undefine></Undefine> <Undefine></Undefine>
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../User;../User/application;../User/board;../User/system/inc;../User/system/bsp;../User/lib/inc;../User/lib/flow;../User/lib/control/inc</IncludePath> <IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../User;../User/application;../User/board;../User/system;../User/system/bsp;../User/system/lib/inc;../User/system/lib/flow;../User/system/lib/control/inc</IncludePath>
</VariousControls> </VariousControls>
</Cads> </Cads>
<Aads> <Aads>
@ -801,94 +801,109 @@
</File> </File>
</Files> </Files>
</Group> </Group>
<Group>
<GroupName>User/lib</GroupName>
<Files>
<File>
<FileName>aes.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\aes.c</FilePath>
</File>
<File>
<FileName>clist.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\clist.c</FilePath>
</File>
<File>
<FileName>cmac.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\cmac.c</FilePath>
</File>
<File>
<FileName>cmd.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\cmd.c</FilePath>
</File>
<File>
<FileName>data_analysis.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\data_analysis.c</FilePath>
</File>
<File>
<FileName>debug.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\debug.c</FilePath>
</File>
<File>
<FileName>filter.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\filter.c</FilePath>
</File>
<File>
<FileName>lib.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\lib.c</FilePath>
</File>
<File>
<FileName>malloc.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\malloc.c</FilePath>
</File>
<File>
<FileName>mlist.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\mlist.c</FilePath>
</File>
<File>
<FileName>pbuf.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\pbuf.c</FilePath>
</File>
<File>
<FileName>sqqueue.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\src\sqqueue.c</FilePath>
</File>
<File>
<FileName>flow_core.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\lib\flow\flow_core.c</FilePath>
</File>
</Files>
</Group>
<Group> <Group>
<GroupName>User/system</GroupName> <GroupName>User/system</GroupName>
<Files> <Files>
<File> <File>
<FileName>btn.c</FileName> <FileName>btn.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\User\system\src\btn.c</FilePath> <FilePath>..\User\system\btn.c</FilePath>
</File> </File>
<File> <File>
<FileName>delay.c</FileName> <FileName>delay.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\User\system\src\delay.c</FilePath> <FilePath>..\User\system\delay.c</FilePath>
</File> </File>
<File> <File>
<FileName>sys.c</FileName> <FileName>sys.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\User\system\src\sys.c</FilePath> <FilePath>..\User\system\sys.c</FilePath>
</File> </File>
</Files>
</Group>
<Group>
<GroupName>User/lib</GroupName>
<Files>
<File>
<FileName>aes.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\aes.c</FilePath>
</File>
<File>
<FileName>clist.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\clist.c</FilePath>
</File>
<File>
<FileName>cmac.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\cmac.c</FilePath>
</File>
<File>
<FileName>cmd.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\cmd.c</FilePath>
</File>
<File>
<FileName>data_analysis.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\data_analysis.c</FilePath>
</File>
<File>
<FileName>debug.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\debug.c</FilePath>
</File>
<File>
<FileName>filter.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\filter.c</FilePath>
</File>
<File>
<FileName>lib.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\lib.c</FilePath>
</File>
<File>
<FileName>malloc.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\malloc.c</FilePath>
</File>
<File>
<FileName>mlist.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\mlist.c</FilePath>
</File>
<File>
<FileName>pbuf.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\pbuf.c</FilePath>
</File>
<File>
<FileName>sqqueue.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\sqqueue.c</FilePath>
</File>
<File>
<FileName>storage.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\storage.c</FilePath>
</File>
<File>
<FileName>wl_flash.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\src\wl_flash.c</FilePath>
</File>
<File>
<FileName>flow_core.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\lib\flow\flow_core.c</FilePath>
</File>
</Files>
</Group>
<Group>
<GroupName>User/system/bsp</GroupName>
<Files>
<File> <File>
<FileName>adcs.c</FileName> <FileName>adcs.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
@ -904,240 +919,11 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\User\system\bsp\gpios.c</FilePath> <FilePath>..\User\system\bsp\gpios.c</FilePath>
</File> </File>
<File>
<FileName>i2cs.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\bsp\i2cs.c</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>0</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Cads>
<interw>2</interw>
<Optim>0</Optim>
<oTime>2</oTime>
<SplitLS>2</SplitLS>
<OneElfS>2</OneElfS>
<Strict>2</Strict>
<EnumInt>2</EnumInt>
<PlainCh>2</PlainCh>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<wLevel>0</wLevel>
<uThumb>2</uThumb>
<uSurpInc>2</uSurpInc>
<uC99>2</uC99>
<uGnu>2</uGnu>
<useXO>2</useXO>
<v6Lang>0</v6Lang>
<v6LangP>0</v6LangP>
<vShortEn>2</vShortEn>
<vShortWch>2</vShortWch>
<v6Lto>2</v6Lto>
<v6WtE>2</v6WtE>
<v6Rtti>2</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Cads>
</FileArmAds>
</FileOption>
</File>
<File>
<FileName>iwdgs.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\bsp\iwdgs.c</FilePath>
</File>
<File>
<FileName>pwms.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\bsp\pwms.c</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>0</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Cads>
<interw>2</interw>
<Optim>0</Optim>
<oTime>2</oTime>
<SplitLS>2</SplitLS>
<OneElfS>2</OneElfS>
<Strict>2</Strict>
<EnumInt>2</EnumInt>
<PlainCh>2</PlainCh>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<wLevel>0</wLevel>
<uThumb>2</uThumb>
<uSurpInc>2</uSurpInc>
<uC99>2</uC99>
<uGnu>2</uGnu>
<useXO>2</useXO>
<v6Lang>0</v6Lang>
<v6LangP>0</v6LangP>
<vShortEn>2</vShortEn>
<vShortWch>2</vShortWch>
<v6Lto>2</v6Lto>
<v6WtE>2</v6WtE>
<v6Rtti>2</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Cads>
</FileArmAds>
</FileOption>
</File>
<File>
<FileName>spis.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\bsp\spis.c</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>0</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Cads>
<interw>2</interw>
<Optim>0</Optim>
<oTime>2</oTime>
<SplitLS>2</SplitLS>
<OneElfS>2</OneElfS>
<Strict>2</Strict>
<EnumInt>2</EnumInt>
<PlainCh>2</PlainCh>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<wLevel>0</wLevel>
<uThumb>2</uThumb>
<uSurpInc>2</uSurpInc>
<uC99>2</uC99>
<uGnu>2</uGnu>
<useXO>2</useXO>
<v6Lang>0</v6Lang>
<v6LangP>0</v6LangP>
<vShortEn>2</vShortEn>
<vShortWch>2</vShortWch>
<v6Lto>2</v6Lto>
<v6WtE>2</v6WtE>
<v6Rtti>2</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Cads>
</FileArmAds>
</FileOption>
</File>
<File> <File>
<FileName>tims.c</FileName> <FileName>tims.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\User\system\bsp\tims.c</FilePath> <FilePath>..\User\system\bsp\tims.c</FilePath>
</File> </File>
<File>
<FileName>uarts.c</FileName>
<FileType>1</FileType>
<FilePath>..\User\system\bsp\uarts.c</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>0</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Cads>
<interw>2</interw>
<Optim>0</Optim>
<oTime>2</oTime>
<SplitLS>2</SplitLS>
<OneElfS>2</OneElfS>
<Strict>2</Strict>
<EnumInt>2</EnumInt>
<PlainCh>2</PlainCh>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<wLevel>0</wLevel>
<uThumb>2</uThumb>
<uSurpInc>2</uSurpInc>
<uC99>2</uC99>
<uGnu>2</uGnu>
<useXO>2</useXO>
<v6Lang>0</v6Lang>
<v6LangP>0</v6LangP>
<vShortEn>2</vShortEn>
<vShortWch>2</vShortWch>
<v6Lto>2</v6Lto>
<v6WtE>2</v6WtE>
<v6Rtti>2</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Cads>
</FileArmAds>
</FileOption>
</File>
</Files> </Files>
</Group> </Group>
<Group> <Group>

View File

@ -1,13 +1,13 @@
:020000040800F2 :020000040800F2
:10000000F01C0020A1010008990C00085D02000806 :10000000F0E50020A1010008AD0C00087D02000809
:10001000950C000817020008D90E00080000000027 :10001000A90C000851020008ED0E000800000000C5
:100020000000000000000000000000009F0C00081D :10002000000000000000000000000000B30C000809
:100030005B020008000000009D0C0008A10C0008F5 :100030007B02000800000000B10C0008B50C0008AD
:10004000BB010008BB010008BB010008BB010008A0 :10004000BB010008BB010008BB010008BB010008A0
:10005000BB010008BB010008BB010008BB01000890 :10005000BB010008BB010008BB010008BB01000890
:10006000BB010008BB010008BB010008BB01000880 :10006000BB010008BB010008BB010008BB01000880
:10007000BB010008BB010008BB010008BB01000870 :10007000BB010008BB010008BB010008BB01000870
:10008000BB010008BB0100080D020008BB0100080D :10008000BB010008BB01000847020008BB010008D3
:10009000BB010008BB010008BB010008BB01000850 :10009000BB010008BB010008BB010008BB01000850
:1000A000BB010008BB010008BB010008BB01000840 :1000A000BB010008BB010008BB010008BB01000840
:1000B000BB010008BB010008BB010008BB01000830 :1000B000BB010008BB010008BB010008BB01000830
@ -16,396 +16,407 @@
:1000E000BB010008BB010008BB010008BB01000800 :1000E000BB010008BB010008BB010008BB01000800
:1000F000BB010008BB010008BB010008BB010008F0 :1000F000BB010008BB010008BB010008BB010008F0
:10010000BB010008BB010008BB010008BB010008DF :10010000BB010008BB010008BB010008BB010008DF
:10011000BB010008BB010008F10D0008BB0100088D :10011000BB010008BB010008050E0008BB01000878
:1001200051020008BB010008BB010008BB01000828 :1001200071020008BB010008BB010008BB01000808
:10013000BB010008BB010008BB010008BB010008AF :10013000BB010008BB010008BB010008BB010008AF
:10014000BB010008BB010008BB010008BB0100089F :10014000BB010008BB010008BB010008BB0100089F
:10015000BB010008BB010008BB010008BB0100088F :10015000BB010008BB010008BB010008BB0100088F
:10016000BB010008BB010008BB010008BB0100087F :10016000BB010008BB010008BB010008BB0100087F
:10017000BB010008BB010008BB0100080000000033 :10017000BB010008BB010008BB0100080000000033
:10018000BB010008BB010008DFF810D000F02CF81C :10018000BB010008BB010008DFF810D000F02CF81C
:1001900000480047C1150008AFF30080F01C0020A4 :1001900000480047D1150008AFF30080F0E50020CB
:1001A0000648804706480047FEE7FEE7FEE7FEE711 :1001A0000648804706480047FEE7FEE7FEE7FEE711
:1001B000FEE7FEE7FEE7FEE7FEE7FEE7DD0D0008EF :1001B000FEE7FEE7FEE7FEE7FEE7FEE7F10D0008DB
:1001C00089010008D2B201E000F8012B491EFBD2E0 :1001C00089010008D2B201E000F8012B491EFBD2E0
:1001D00070470022F6E710B513460A460446194652 :1001D00070470022F6E710B513460A460446194652
:1001E000FFF7F0FF204610BD064C074D06E0E06823 :1001E000FFF7F0FF204610BD064C074D06E0E06823
:1001F00040F0010394E8070098471034AC42F6D36E :1001F00040F0010394E8070098471034AC42F6D36E
:10020000FFF7C6FFE01800081019000810B500201D :10020000FFF7C6FF341900085419000830B58C18E0
:1002100000F0CAFE10BD00BFFEE7000030B5024688 :1002100010F8012B12F00F0301D110F8013B120965
:100220000B4600BF7AB90220084C616920EA01043C :1002200006D110F8012B03E010F8015B01F8015B27
:1002300001EA000544EA0544044DAC6100BF01E059 :100230005B1EF9D101E001F8013B521EFBD1A14246
:1002400000BF00BFFCE700BF012030BD001002402E :10024000E6D3002030BD10B5002000F0B5FE10BD93
:1002500010B5002000F07CFE10BD704700BFFEE727 :1002500000BFFEE770B504460D4600BF2CB901F0A3
:100260002DE9F04105460C460026606800B100BF4C :1002600003FB01E000BF00BFFCE700BF012070BD41
:10027000134800F04FF80746124800F04BF80743C8 :1002700010B5002000F076FE10BD704700BFFEE70D
:10028000114800F047F80743AFB9606860B1D4E99E :100280002DE9F04105460C460026606800B100BF2C
:1002900000010843A1680843E168084369680B4A04 :10029000134800F049F80746124800F045F80743B4
:1002A00011400843686007E0686808490840216811 :1002A000114800F041F80743AFB9606860B1D4E984
:1002B0000843686000E001263046BDE8F081000098 :1002B00000010843A1680843E168084369680B4AE4
:1002C000002001400021014000220140E010FCFF1D :1002C00011400843686007E06868084908402168F1
:1002D000816821F0010181607047000070B504461B :1002D0000843686000E001263046BDE8F081000078
:1002E0000D460026204600F015F870B9A968286868 :1002E000002001400021014000220140E010FCFFFD
:1002F00008436168064A114008436060A06820F422 :1002F00070B504460D460026204600F015F870B98A
:10030000006069680843A06000E00126304670BDC7 :10030000A968286808436168064A1140084360608C
:10031000FFFEFFFC0146886800F001007047000006 :10031000A06820F4006069680843A06000E001263E
:1003200070B504460D460026686800B100BF20463F :10032000304670BDFFFEFFFC0146886800F001000A
:10033000FFF7F0FF00BB686830B1606820F46840E8 :100330007047000070B504460D460026686800B19D
:10034000A9680843606003E0606820F4684060606A :1003400000BF2046FFF7F0FF00BB686830B160686F
:10035000286800F07060E968084329690843A168CB :1003500020F46840A9680843606003E0606820F406
:10036000074A11400843A0606868E16A21F47001FF :1003600068406060286800F07060E96808432969A7
:100370000143E16200BF00E00126304670BD00008D :100370000843A168074A11400843A0606868E16A21
:10038000FDFCFFC070B501F440744FF4407595FA60 :1003800021F470010143E16200BF00E00126304624
:10039000A5F5B5FA85F5EC4000F12C0505EB8403D5 :1003900070BD0000FDFCFFC070B501F440744FF467
:1003A0001C6801F01F061F25B540AC4302F01F0575 :1003A000407595FAA5F5B5FA85F5EC4000F12C05F8
:1003B00001F01F06B5402C431C6070BD70B501F004 :1003B00005EB84031C6801F01F061F25B540AC4304
:1003C00000744FF0007595FAA5F5B5FA85F5EC4087 :1003C00002F01F0501F01F06B5402C431C6070BDF4
:1003D00000F10C0505EB84031C6801F0F8754FF083 :1003D00070B501F000744FF0007595FAA5F5B5FA07
:1003E000F87696FAA6F6B6FA86F6F5400726AE40F7 :1003E00085F5EC4000F10C0505EB84031C6801F079
:1003F000B44301F0F8754FF0F87696FAA6F6B6FA1F :1003F000F8754FF0F87696FAA6F6B6FA86F6F54056
:1004000086F6F54002FA05F52C431C6070BD426883 :100400000726AE40B44301F0F8754FF0F87696FA3F
:1004100022F440020A4342607047426822F44002DC :10041000A6F6B6FA86F6F54002FA05F52C431C60FE
:100420000A4342607047000008B505490968014366 :1004200070BD426822F440020A434260704742684D
:10043000034A1160114609680140009100BF08BDE0 :1004300022F440020A4342607047000008B50549B3
:1004400030380240F0B502460B46002400211868FF :1004400009680143034A116011460968014000919F
:1004500090FAA0F0B0FA80F48AE00125A54018686F :1004500000BF08BD30380240F0B502460B4600240C
:1004600000EA050100297DD05868012802D05868AB :100460000021186890FAA0F0B0FA80F48AE0012523
:1004700002281CD19868956891FAA1F6B6FA86F61A :10047000A540186800EA050100297DD058680128C8
:1004800077000326BE40B54391FAA1F6B6FA86F688 :1004800002D0586802281CD19868956891FAA1F6A4
:10049000760000FA06F63543956000BFD8685568C7 :10049000B6FA86F677000326BE40B54391FAA1F678
:1004A0008D4301FB00F63543556000BF00BF18695E :1004A000B6FA86F6760000FA06F63543956000BF88
:1004B000D56891FAA1F6B6FA86F677000326BE4013 :1004B000D86855688D4301FB00F63543556000BF91
:1004C000B54391FAA1F6B6FA86F6760000FA06F67A :1004C00000BF1869D56891FAA1F6B6FA86F67700EA
:1004D0003543D56000BF5868022831D191FAA1F0A8 :1004D0000326BE40B54391FAA1F6B6FA86F6760039
:1004E000B0FA80F0082814D25869156A91FAA1F67A :1004E00000FA06F63543D56000BF5868022831D1BE
:1004F000B6FA86F6B7000F26BE40B54391FAA1F6CC :1004F00091FAA1F0B0FA80F0082814D25869156A70
:10050000B6FA86F6B60000FA06F63543156200BF65 :1005000091FAA1F6B6FA86F6B7000F26BE40B543BB
:1005100016E05869556A0E0A96FAA6F6B6FA86F6F5 :1005100091FAA1F6B6FA86F6B60000FA06F6354369
:10052000B7000F26BE40B5430E0A96FAA6F6B6FAF5 :10052000156200BF16E05869556A0E0A96FAA6F6DB
:1005300086F6B60000FA06F63543556200BF00BFE6 :10053000B6FA86F6B7000F26BE40B5430E0A96FA05
:100540005868156891FAA1F6B6FA86F67700032680 :10054000A6F6B6FA86F6B60000FA06F63543556208
:10055000BE40B54391FAA1F6B6FA86F6760000FAE7 :1005500000BF00BF5868156891FAA1F6B6FA86F692
:1005600006F600E003E03543156000BF00BF641CE1 :1005600077000326BE40B54391FAA1F6B6FA86F6A7
:100570001868E04000287FF470AFF0BD10B5426904 :10057000760000FA06F600E003E03543156000BFA0
:1005800021EA020302EA010443EA0443836110BD45 :1005800000BF641C1868E04000287FF470AFF0BD25
:1005900002480068401C0149086070474C00002078 :1005900010B5426921EA020302EA010443EA044376
:1005A0004FF47A71B0FBF1F2521E4FF0E0235A6122 :1005A000836110BD02480068401C01490860704723
:1005B00000229A6105221A6100BF70470149086054 :1005B000240000204FF47A71B0FBF1F2521E4FF08C
:1005C000704700000000002010B5024613682C4858 :1005C000E0235A6100229A6105221A6100BF704738
:1005D00082420ED0B2F1804F0BD02A48824208D01E :1005D00001490860704700000000002010B5024685
:1005E0002948824205D02948824202D028488242C6 :1005E00013682C4882420ED0B2F1804F0BD02A48BB
:1005F00004D123F070004C6840EA04032048824292 :1005F000824208D02948824205D02948824202D04E
:1006000020D0B2F1804F1DD01E4882421AD01E4821 :100600002848824204D123F070004C6840EA040379
:10061000824217D01D48824214D01D48824211D018 :100610002048824220D0B2F1804F1DD01E48824235
:100620001C4882420ED01C4882420BD01B4882429A :100620001AD01E48824217D01D48824214D01D485D
:1006300008D01B48824205D01A48824202D01A488C :10063000824211D01C4882420ED01C4882420BD00C
:10064000824204D123F44070CC6840EA0403136072 :100640001B48824208D01B48824205D01A48824289
:100650008868D06200BF0888906200BF0848824264 :1006500002D01A48824204D123F44070CC6840EAA8
:1006600002D00B48824203D10869106300BF00BF6B :10066000040313608868D06200BF0888906200BFEE
:1006700000BF506940F00100506100BF002010BD74 :100670000848824202D00B48824203D108691063C5
:10068000000001400004004000080040000C004051 :1006800000BF00BF00BF506940F00100506100BFD3
:100690000004014000400140004401400048014086 :10069000002010BD000001400004004000080040A0
:1006A00000180040001C004000200040014608697E :1006A000000C0040000401400040014000440140B3
:1006B00000F00100704708B54FF0E0210969009192 :1006B0000048014000180040001C0040002000409D
:1006C00000BF411C01B1401C06E04FF0E021096968 :1006C0000146086900F00100704708B54FF0E021CD
:1006D00001F4803101B1401E0028F6D108BD0000B0 :1006D0000969009100BF411C01B1401C06E04FF0C8
:1006E0002DE9F0418EB000200B900C900D9014215C :1006E000E021096901F4803101B1401E0028F6D1F2
:1006F00006A8FFF76EFD002002900390049005907D :1006F00008BD00002DE9F0418EB000200B900C9059
:100700004FF48070874909680143864A1160114699 :100700000D90142106A8FFF764FD002002900390CD
:1007100009680140019100BF00BF834800210A46DB :10071000049005904FF48070874909680143864A28
:10072000824B5B5CC35823F0606313437F4C645C73 :100720001160114609680140019100BF00BF834874
:10073000035100BF00BF7D4B5B5CC35823F0C00377 :1007300000210A46824B5B5CC35823F0606313437D
:1007400013437A4C645C035100BF00BF774B5B5C82 :100740007F4C645C035100BF00BF7D4B5B5CC358B2
:10075000C35823F440331343744C645C035100BF0B :1007500023F0C00313437A4C645C035100BF00BF15
:100760008215724B5B5CC35823F4907313436F4C38 :10076000774B5B5CC35823F440331343744C645C95
:10077000645C035100BF0A466C4B5B5CC35823F4B6 :10077000035100BF8215724B5B5CC35823F4907326
:1007800000731343694C645C035100BF0215674B4F :1007800013436F4C645C035100BF0A466C4B5B5CC7
:100790005B5CC35823F480631343644C645C035173 :10079000C35823F400731343694C645C035100BFD6
:1007A00000BFC214614B5B5CC35823F4C0531343B6 :1007A0000215674B5B5CC35823F480631343644CAE
:1007B0005E4C645C035100BF92005C4B5B5CC358B1 :1007B000645C035100BFC214614B5B5CC35823F4FB
:1007C00023F4C0431343594C645C035100BF00BF82 :1007C000C05313435E4C645C035100BF92005C4B0A
:1007D000564A525C0244526922F00402534B5B5C5D :1007D0005B5CC35823F4C0431343594C645C03511E
:1007E00003445A6100BF1221514B1B68C3F302201E :1007E00000BF00BF564A525C0244526922F0040224
:1007F000002425460346C3F1070CBCF1040F02D9BF :1007F000534B5B5C03445A6100BF1221514B1B6891
:100800004FF0040C01E0C3F1070C674603F1040C40 :10080000C3F30220002425460346C3F1070CBCF1C4
:10081000BCF1070F02D24FF0000C01E0A3F1030C72 :10081000040F02D94FF0040C01E0C3F1070C674646
:1008200066464FF0010C0CFA07FCACF1010C0CEA27 :1008200003F1040CBCF1070F02D24FF0000C01E001
:10083000040C0CFA06FC4FF0010808FA06F8A8F1BF :10083000A3F1030C66464FF0010C0CFA07FCACF177
:10084000010808EA05084CEA080200BF002904DB99 :10084000010C0CEA040C0CFA06FC4FF0010808FA43
:100850001007030E3748435407E01007040E3448CE :1008500006F8A8F1010808EA05084CEA080200BFFA
:100860000C3001F00F031B1FC45400BF12200028DE :10086000002904DB1007030E3748435407E0100744
:1008700009DB00F01F02012191404209920002F1C0 :10087000040E34480C3001F00F031B1FC45400BF9A
:10088000E022C2F8001100BF00200B900C904FF442 :100880001220002809DB00F01F02012191404209DB
:1008900080700D900BA92848FFF720FD00200690DE :10089000920002F1E022C2F8001100BF00200B908C
:1008A0004FF48010079000200890022009904FF428 :1008A0000C904FF480700D900BA92848FFF720FDA5
:1008B00040700A9006A92048FFF732FD00201E492B :1008B000002006904FF4801007900020089002203E
:1008C000896821F4806101431B4A916000BF4FF4A5 :1008C00009904FF440700A9006A92048FFF732FDC6
:1008D000803002900020039002A91848FFF7C0FC66 :1008D00000201E49896821F4806101431B4A916010
:1008E000174A4FF400711448FFF74CFD02221449D7 :1008E00000BF4FF4803002900020039002A9184806
:1008F0001148FFF763FD4FF400011048FFF787FD33 :1008F000FFF7C6FC174A4FF400711448FFF74CFD90
:10090000104A910D0C48FFF73DFD02220D490A489F :10090000022214491148FFF763FD4FF4000110481B
:10091000FFF754FD4FF400010848FFF778FD0EB0D3 :10091000FFF787FD104A910D0C48FFF73DFD0222BD
:10092000BDE8F081443802400064024058180008D5 :100920000D490A48FFF754FD4FF400010848FFF74E
:100930000CED00E000E400E0002001400023014055 :1009300078FD0EB0BDE8F08144380240006402400A
:1009400010002081110050812DE9F8414FF4800002 :10094000AC1800080CED00E000E400E000200140DD
:100950002E49096801432D4A11601146096801407A :100950000023014010002081110050812DE9F84151
:10096000009100BF00BF3821294B1B68C3F3022050 :100960004FF480002E49096801432D4A1160114659
:10097000002425460346C3F1070CBCF1040F02D93D :1009700009680140009100BF00BF3821294B1B6866
:100980004FF0040C01E0C3F1070C674603F1040CBF :10098000C3F30220002425460346C3F1070CBCF143
:10099000BCF1070F02D24FF0000C01E0A3F1030CF1 :10099000040F02D94FF0040C01E0C3F1070C6746C5
:1009A00066464FF0010C0CFA07FCACF1010C0CEAA6 :1009A00003F1040CBCF1070F02D24FF0000C01E080
:1009B000040C0CFA06FC4FF0010808FA06F8A8F13E :1009B000A3F1030C66464FF0010C0CFA07FCACF1F6
:1009C000010808EA05084CEA080200BF002904DB18 :1009C000010C0CEA040C0CFA06FC4FF0010808FAC2
:1009D0001007030E0F48435407E01007040E0C489D :1009D00006F8A8F1010808EA05084CEA080200BF79
:1009E0000C3001F00F031B1FC45400BF3820002837 :1009E000002904DB1007030E0F48435407E01007EB
:1009F00009DB00F01F02012191404209920002F13F :1009F000040E0C480C3001F00F031B1FC45400BF41
:100A0000E022C2F8001100BFBDE8F8813038024092 :100A00003820002809DB00F01F0201219140420933
:100A10000CED00E000E400E000B587B0182101A86B :100A1000920002F1E022C2F8001100BFBDE8F881A7
:100A2000FFF7D7FB1020FFF7FFFC4FF48070FFF7B4 :100A2000303802400CED00E000E400E000B587B093
:100A3000FBFC0420FFF7F8FC2020FFF7F5FC8020EA :100A3000182101A8FFF7CDFB1020FFF7FFFC4FF4B2
:100A4000FFF7F2FC0120FFF7EFFC0220FFF7ECFCC0 :100A40008070FFF7FBFC0420FFF7F8FC2020FFF785
:100A50004020FFF7E9FC0820FFF7E6FC03203A49B5 :100A5000F5FC8020FFF7F2FC0120FFF7EFFC0220FD
:100A6000886100BF4FF6FC700190032002900020C7 :100A6000FFF7ECFC4020FFF7E9FC0820FFF7E6FC6D
:100A7000059001A93448FFF7E5FC40F6FF700190AE :100A700003203A49886100BF4FF6FC7001900320C3
:100A8000032002900020059001A93048FFF7DAFC0E :100A800002900020059001A93448FFF7E5FC40F6EC
:100A900043F6FF700190032002900020059001A909 :100A9000FF700190032002900020059001A93048CA
:100AA0002B48FFF7CFFC4FF6FF7001900320029018 :100AA000FFF7DAFC43F6FF7001900320029000206C
:100AB0000020059001A92748FFF7C4FC49F6FF7004 :100AB000059001A92B48FFF7CFFC4FF6FF7001907E
:100AC0000190032002900020059001A92248FFF721 :100AC000032002900020059001A92748FFF7C4FCED
:100AD000B9FC4FF6FC7001900320029000200590B5 :100AD00049F6FF700190032002900020059001A9C3
:100AE00001A91E48FFF7AEFC4FF6FF7001900320EE :100AE0002248FFF7B9FC4FF6FC70019003200290FA
:100AF00002900020059001A91948FFF7A3FC4FF6CA :100AF0000020059001A91E48FFF7AEFC4FF6FF70DD
:100B0000FF700190032002900020059001A9154874 :100B00000190032002900020059001A91948FFF7E9
:100B1000FFF798FC4FF6FF70019003200290002031 :100B1000A3FC4FF6FF700190032002900020059087
:100B2000059001A91048FFF78DFC032001900120DA :100B200001A91548FFF798FC4FF6FF7001900320CC
:100B300002900220039000200490059001A9024831 :100B300002900020059001A91048FFF78DFC0320CA
:100B4000FFF780FC07B000BD00100240002002400B :100B40000190012002900220039000200490059063
:100B5000000802400014024000000240001C024055 :100B500001A90248FFF780FC07B000BD0010024069
:100B60000004024000180240000C02402DE9F04150 :100B60000020024000080240001402400000024041
:100B700086B0142101A8FFF72CFB10204149096819 :100B7000001C02400004024000180240000C024029
:100B80000143404A1160114609680140009100BFCD :100B80002DE9F04186B0142101A8FFF722FB1020C7
:100B900000BF36213C4B1B68C3F30220062400250E :100B9000414909680143404A116011460968014012
:100BA0000346C3F1070CBCF1040F02D94FF0040C4B :100BA000009100BF00BF36213C4B1B68C3F30220FD
:100BB00001E0C3F1070C674603F1040CBCF1070F19 :100BB000062400250346C3F1070CBCF1040F02D93B
:100BC00002D24FF0000C01E0A3F1030C66464FF097 :100BC0004FF0040C01E0C3F1070C674603F1040C7D
:100BD000010C0CFA07FCACF1010C0CEA040C0CFA49 :100BD000BCF1070F02D24FF0000C01E0A3F1030CAF
:100BE00006FC4FF0010808FA06F8A8F1010808EA27 :100BE00066464FF0010C0CFA07FCACF1010C0CEA64
:100BF00005084CEA080200BF002904DB1007030EB9 :100BF000040C0CFA06FC4FF0010808FA06F8A8F1FC
:100C00002248435407E01007040E1F480C3001F03F :100C0000010808EA05084CEA080200BF002904DBD5
:100C10000F031B1FC45400BF3620002809DB00F05F :100C10001007030E2248435407E01007040E1F4834
:100C20001F02012191404209920002F1E022C2F824 :100C20000C3001F00F031B1FC45400BF36200028F6
:100C3000001100BF44F29F10ADF8040000200290A4 :100C300009DB00F01F02012191404209920002F1FC
:100C40006320039001A91248FFF7BEFC00BF1048C3 :100C4000E022C2F8001100BF42F2CF00ADF804006C
:100C5000006820F080000E49086000BF002049684D :100C5000002002906320039001A91248FFF7BEFC18
:100C600021F0700101430A4A516000BF00BF1046E5 :100C600000BF1048006820F080000E49086000BFF7
:100C7000806820F080001146886000BF06B0BDE8A3 :100C70000020496821F0700101430A4A516000BF19
:100C8000F0810000403802400CED00E000E400E09C :100C800000BF1046806820F080001146886000BFD9
:100C90000010004000BFFEE700BFFEE7704770474E :100C900006B0BDE8F0810000403802400CED00E0F5
:100CA0007047000070B505204749096821F0070129 :100CA00000E400E00010004000BFFEE700BFFEE7E8
:100CB0000143454A116000BF00BF00BF42480068C1 :100CB000704770477047000070B5052047490968C4
:100CC00000F007000528F8D14FF480403F4909683B :100CC00021F007010143454A116000BF00BF00BF8A
:100CD00021F4804101433D4A116000BF00BF3C4800 :100CD0004248006800F007000528F8D14FF4804032
:100CE000006840F480303A49086000BF00BF00BF90 :100CE0003F49096821F4804101433D4A116000BF3A
:100CF00037480068C0F340400028F8D04FF4800027 :100CF00000BF3C48006840F480303A49086000BFBB
:100D00000421A822002340EA010444EA8214304D61 :100D000000BF00BF37480068C0F340400028F8D05B
:100D10002D1D2D682F4E35402C432D4D2D1D2C6043 :100D10004FF480000421A822002340EA010444EAA1
:100D20002C46246824F440341C432C6000BF00BFD0 :100D20008214304D2D1D2D682F4E35402C432D4DF6
:100D3000281F006840F08070291F086000BF00BFB6 :100D30002D1D2C602C46246824F440341C432C6068
:100D400000BF23480068C0F340600028F8D000BF0F :100D400000BF00BF281F006840F08070291F0860A6
:100D500000BF1E484068C0F380300028F8D0002053 :100D500000BF00BF00BF23480068C0F34060002808
:100D60001B490831096821F0F0010143184A083293 :100D6000F8D000BF00BF1E484068C0F380300028A4
:100D7000116000BF4FF4A0501146096821F4E05102 :100D7000F8D000201B490831096821F0F001014337
:100D80000143116000BF4FF400401146096821F48F :100D8000184A0832116000BF4FF4A050114609689C
:100D900060410143116000BF02201146096821F043 :100D900021F4E0510143116000BF4FF400401146BF
:100DA00003010143116000BF00BF00BF08480830C5 :100DA000096821F460410143116000BF022011462F
:100DB000006800F00C000828F7D10748FFF7F0FBA7 :100DB000096821F003010143116000BF00BF00BFBB
:100DC0000548FFF7FBFB70BD003C0240007000408F :100DC00008480830006800F00C000828F7D10748F0
:100DD000003802400080BFFF007A030A0348006821 :100DD000FFF7F0FB0548FFF7FBFB70BD003C02404E
:100DE00040F47000014908607047000088ED00E0A1 :100DE00000700040003802400080BFFF007A030A14
:100DF00010B53748FFF75AFC012868D100BF00BF83 :100DF0000348006840F47000014908607047000033
:100E000033480069C0F3400060B100BF3048C0689B :100E000088ED00E010B53748FFF75AFC012868D19B
:100E1000C0F3400030B100BF6FF002002C49086100 :100E100000BF00BF33480069C0F3400060B100BFAD
:100E200000BF00BF00BF2A480069C0F3800060B166 :100E20003048C068C0F3400030B100BF6FF002002E
:100E300000BF2748C068C0F3800030B100BF6FF02A :100E30002C49086100BF00BF00BF2A480069C0F309
:100E400004002349086100BF00BF00BF20480069BB :100E4000800060B100BF2748C068C0F3800030B1A7
:100E5000C0F3C00060B100BF1D48C068C0F3C0004F :100E500000BF6FF004002349086100BF00BF00BF5E
:100E600030B100BF6FF008001949086100BF00BF32 :100E600020480069C0F3C00060B100BF1D48C068E1
:100E700000BF17480069C0F3001060B100BF1448FC :100E7000C0F3C00030B100BF6FF00800194908612D
:100E8000C068C0F3001030B100BF6FF0100010490F :100E800000BF00BF00BF17480069C0F3001060B189
:100E9000086100BF00BF0E48FFF708FC01280CD115 :100E900000BF1448C068C0F3001030B100BF6FF04D
:100EA00000BF0B48C06800F0010030B100BF6FF018 :100EA00010001049086100BF00BF0E48FFF708FCA2
:100EB00001000749086100BF00BF00BFFFF768FBE2 :100EB00001280CD100BF0B48C06800F0010030B120
:100EC00000BF04480068401C0249086000BF10BD14 :100EC00000BF6FF001000749086100BF00BF00BF0D
:100ED000001000404400002000BFFEE702E008C808 :100ED000FFF768FB00BF04480068401C0249086037
:100EE000121F08C1002AFAD170477047002001E0A4 :100EE00000BF10BD001000405800002000BFFEE70A
:100EF00001C1121F002AFBD170470000014601F119 :100EF00002E008C8121F08C1002AFAD170477047E3
:100F0000100000E0001D02681AB9024A12689042FF :100F0000002001E001C1121F002AFBD17047000040
:100F1000F8D370472400002010B50648046803E0A9 :100F1000014601F1100000E0001D02681AB9024A02
:100F20002046FFF7EBFF0446034800688442F7D3EE :100F200012689042F8D370473800002010B5064888
:100F300010BD0000200000202400002010B501E0BA :100F3000046803E02046FFF7EBFF0446034800681F
:100F400000F8011B131EA2F10104A2B2F8D110BDDA :100F40008442F7D310BD0000340000203800002098
:100F500070B5054605EBC500124901EB80040CB1E4 :100F500010B501E000F8011B131EA2F10104A2B2BA
:100F6000012100E00021084640F22911FFF756F95F :100F6000F8D110BD70B5054605EBC500114901EB80
:100F700060680168C1F3C02139B160684FF4006155 :100F700080040CB1012100E00021084640F2291153
:100F8000816000BF2068FFF7A3F960680168C1F3C2 :100F8000FFF768F960680168C1F3C02129B16068A2
:100F9000402129B160684FF40071816000BF00BF3B :100F90004FF40061816000BF00BF60680168C1F369
:100FA00070BD00008018002070B5054605EBC50037 :100FA000402129B160684FF40071816000BF00BF2B
:100FB0000D4901EB80040CB1012100E0002108463D :100FB00070BD000080E1002070B5054605EBC5005E
:100FC0004FF4A071FFF72AF920680168C1F34011BE :100FC0000D4901EB80040CB1012100E0002108462D
:100FD00041B16069401C606120686FF020010160D0 :100FD0004FF49F71FFF73EF920680168C1F340119B
:100FE00000BF00BF70BD0000801800200146002037 :100FE00041B16069401C606120686FF020010160C0
:100FF00001F001020AB1421CD0B201F002020AB1B2 :100FF00000BF00BF70BD000080E10020014600205E
:10100000421CD0B201F004020AB1421CD0B201F07D :1010000001F001020AB1421CD0B201F002020AB1A1
:1010100008020AB1421CD0B201F010020AB1421C0F :10101000421CD0B201F004020AB1421CD0B201F06D
:10102000D0B201F020020AB1421CD0B201F040025D :1010200008020AB1421CD0B201F010020AB1421CFF
:101030000AB1421CD0B201F080020AB1421CD0B207 :10103000D0B201F020020AB1421CD0B201F040024D
:1010400001F480720AB1421CD0B201F400720AB1FC :101040000AB1421CD0B201F080020AB1421CD0B2F7
:10105000421CD0B201F480620AB1421CD0B201F449 :1010500001F480720AB1421CD0B201F400720AB1EC
:1010600000620AB1421CD0B201F480520AB1421CA3 :10106000421CD0B201F480620AB1421CD0B201F439
:10107000D0B201F400520AB1421CD0B201F4804255 :1010700000620AB1421CD0B201F480520AB1421C93
:101080000AB1421CD0B201F400420AB1421CD0B2F3 :10108000D0B201F400520AB1421CD0B201F4804245
:1010900001F480320AB1421CD0B201F400220AB13C :101090000AB1421CD0B201F400420AB1421CD0B2E3
:1010A000421CD0B201F480220AB1421CD0B201F439 :1010A00001F480320AB1421CD0B201F400220AB12C
:1010B00000320AB1421CD0B2704700002DE9FF4F48 :1010B000421CD0B201F480220AB1421CD0B201F429
:1010C00081B006460F469046DDE90F95032E01DA02 :1010C00000320AB1421CD0B2704700002DE9FF4F38
:1010D000012100E0002108461C21FFF79FF80FB115 :1010D00081B006460F469046DDE90F95032E01DAF2
:1010E000012100E0002108461D21FFF797F8B8F123 :1010E000012100E0002108461C21FFF7B3F80FB1F1
:1010F000000F01D0012100E0002108461E21FFF76A :1010F000012100E0002108461D21FFF7ABF8B8F1FF
:101100008DF8B9F1000F01DD012100E00021084652 :10110000000F01D0012100E0002108461E21FFF759
:101110001F21FFF783F806EBC600744901EB80043A :10111000A1F8B9F1000F01DD012100E0002108462E
:10112000242200212046FFF709FF2760C4F804802D :101120001F21FFF797F806EBC600744901EB800416
:101130000498A0600E98E0602561A4F818902846F5 :10113000242200212046FFF70BFF2760C4F804801B
:10114000FFF754FFA076A07E00FB09F0A083A08BE0 :101140000498A0600E98E0602561A4F818902846E5
:101150004FEA400A5146012000F060FB2062216AFC :10115000FFF754FFA076A07E00FB09F0A083A08BD0
:1011600009B1012100E0002108463221FFF756F8BD :101160004FEA400A5146012000F060FB2062216AEC
:10117000A18B49040A0C0021206AFFF7DFFE201D25 :1011700009B1012100E0002108463221FFF76AF899
:1011800007C85B4B5B5CC35823F060631343DFF815 :10118000A18B49040A0C0021206AFFF7E1FE201D13
:1011900060C11CF801C040F80C3000BF554AD4E9CA :1011900007C85B4B5B5CC35823F060631343DFF805
:1011A0000101534B5B5CC358DFF84CC103EA0C03ED :1011A00060C11CF801C040F80C3000BF554AD4E9BA
:1011B0001343DFF83CC11CF801C040F80C3000BFFD :1011B0000101534B5B5CC358DFF84CC103EA0C03DD
:1011C0004FF0000BD4E900A0A1684FF0000ECDF85D :1011C0001343DFF83CC11CF801C040F80C3000BFED
:1011D00000E0BBF1000F04D10AF14C0ECDF800E0A5 :1011D0004FF0000BD4E900A0A1684FF0000ECDF84D
:1011E00003E0DFF818E1CDF800E0009AD4E901ABA4 :1011E00000E0BBF1000F04D10AF14C0ECDF800E095
:1011F000236ADFF8FCE01EF80BE05AF80EE00EF070 :1011F00003E0DFF818E1CDF800E0009AD4E901AB94
:10120000C00C00BFBCF1400F0ED1DFF8E4A01AF80B :10120000236ADFF8FCE01EF80BE05AF80EE00EF05F
:1012100001A08244CAF80C20DFF8D4A01AF801A07B :10121000C00C00BFBCF1400F0ED1DFF8E4A01AF8FB
:101220008244CAF808300DE0DFF8C4A01AF801A023 :1012200001A08244CAF80C20DFF8D4A01AF801A06B
:101230008244CAF80820DFF8B8A01AF801A0824456 :101230008244CAF808300DE0DFF8C4A01AF801A013
:10124000CAF80C3000BFA28BD4E90101284B5B5CCB :101240008244CAF80820DFF8B8A01AF801A0824446
:1012500003445B686FF30F031343DFF894C01CF87B :10125000CAF80C3000BFA28BD4E90101284B5B5CBB
:1012600001C08444CCF8043000BFD4E90101204A15 :1012600003445B686FF30F031343DFF894C01CF86B
:10127000525C825842F001021D4B5B5CC25000BFC1 :1012700001C08444CCF8043000BFD4E90101204A05
:1012800002212068826822F002020A43826000BFC5 :10128000525C825842F001021D4B5B5CC25000BFB1
:101290004FF440712068826822F440720A438260F1 :1012900002212068826822F002020A43826000BFB5
:1012A00000BF05F4002028B14FF4000113480838AE :1012A0004FF440712068826822F440720A438260E1
:1012B000FFF7B3F805F4003028B14FF400010F48F0 :1012B00000BF05F4002028B14FF40001134808389E
:1012C0000838FFF7AAF80A20FFF7F5F920688168C7 :1012C000FFF7B5F805F4003028B14FF400010F48DE
:1012D00041F00101816000BF2068816841F08041D8 :1012D0000838FFF7ACF80A20FFF7F7F920688168B3
:1012E000816000BF05B0BDE8F08F000080180020CD :1012E00041F00101816000BF2068816841F08041C8
:1012F000B4180008002D02001F80FCFF08230140E5 :1012F000816000BF05B0BDE8F08F000080E10020F4
:101300002DE9F04705468846032D01DA012100E06A :1013000008190008002D02001F80FCFF082301407F
:1013100000210846EE21FEF781FF4FF0000900266C :101310002DE9F04705468846032D01DA012100E05A
:1013200005EBC500104901EB80040CB1012100E080 :1013200000210846EE21FEF795FF4FF00009002648
:1013300000210846F221FEF771FF206A00EB480702 :1013300005EBC500104901EB80040CB1012100E070
:10134000002006E039880E44411C88B2A17E07EBDC :1013400000210846F221FEF785FF206A00EB4807DE
:101350004107218B8142F5DC208BB6FBF0F01FFAB0 :10135000002006E039880E44411C88B2A17E07EBCC
:1013600080F94846BDE8F087801800200C4B1988AA :101360004107218B8142F5DC208BB6FBF0F01FFAA0
:101370009B1C1A88431A00EE903AF8EEE01A531AB2 :1013700080F94846BDE8F08780E100200C4B1988D1
:1013800000EE903AF8EEE00A81EEA01ADFED051AC1 :101380009B1C1A88431A00EE903AF8EEE01A531AA2
:10139000F3EE0E0A41EE210AB0EE600A704700003B :1013900000EE903AF8EEE00A81EEA01ADFED051AB1
:1013A0002C7AFF1F0000A0420E49098840F6E44253 :1013A000F3EE0E0A41EE210AB0EE600A704700002B
:1013B000514340F6FF72B1FBF2F100EE101AB8EEA5 :1013B0002C7AFF1F0000A0420E49098840F6E44243
:1013C000400AF0EE400A00EE100AB8EE400A80EE45 :1013C000514340F6FF72B1FBF2F100EE101AB8EE95
:1013D000801A9FED050A21EE001ADFED041A81EE56 :1013D000400AF0EE400A00EE100AB8EE400A80EE35
:1013E000210A70472A7AFF1F00F07F4500007A44E7 :1013E000801A9FED050A21EE001ADFED041A81EE46
:1013F00000200B4908600B49086000BF00BF0A4885 :1013F000210A70472A7AFF1F00F07F4500007A44D7
:10140000006840F001000849086000BF00BF0846BE :1014000000200B4908600B49086000BF00BF0A4874
:10141000C06840F00100C86000BF00BF7047000016 :10141000006840F001000849086000BF00BF0846AE
:1014200008000020100000200010004010B5034804 :10142000C06840F00100C86000BF00BF7047000006
:1014300000F01CF8024800F087F810BD08000020FA :1014300008000020100000200010004010B50348F4
:10144000100000200EB54FF420204FF4C871002288 :1014400000F01CF8024800F087F810BD08000020EA
:101450001346CDE900210290024A03490020FFF71C :10145000100000200EB54FF420204FF4C871002278
:101460002DFE0EBD006402400020014038B5044648 :101460001346CDE900210290024A03490020FFF70C
:1014700000200090206810B112281DD112E000BF9A :101470002DFE0EBD006402400020014038B5044638
:1014800000F02AF80F4880ED000A00F041F80D48FE :1014800000200090206810B112281DD112E000BF8A
:1014900080ED010A00BF0C480068606000BF1220A8 :1014900000F02AF80F4880ED000A00F041F80D48EE
:1014A000206000BF084960680968081A642801D2F2 :1014A00080ED010A00BF0C480068606000BF122098
:1014B000002038BD00BFE3E700202060009003203B :1014B000206000BF084960680968081A642801D2E2
:1014C000F7E70000180000204400002001490860F0 :1014C000002038BD00BFE3E700202060009003202B
:1014D000704700004800002010B52DED028B9FEDF5 :1014D000F7E70000180000205800002001490860CC
:1014E0000A0AB0EE408A00210846FFF709FF0749C3 :1014E000704700002000002010B52DED028B9FED0D
:1014F00008800888FFF73AFFB0EE408AB0EE480A4D :1014F0000A0AB0EE408A00210846FFF709FF0749B3
:10150000BDEC028B10BD00000000000004000020B4 :1015000008800888FFF73AFFB0EE408AB0EE480A3C
:1015100010B52DED028B9FED0A0AB0EE408A012135 :10151000BDEC028B10BD00000000000004000020A4
:101520000020FFF7EDFE074948804888FFF73CFFA1 :1015200010B52DED028B9FED0A0AB0EE408A012125
:10153000B0EE408AB0EE480ABDEC028B10BD000050 :101530000020FFF7EDFE074948804888FFF73CFF91
:10154000000000000400002038B504460020009090 :10154000B0EE408AB0EE480ABDEC028B10BD000040
:10155000206810B1252816D10BE000BF012000F053 :10155000000000000400002038B504460020009080
:1015600019F800BF0A480068606000BF25202060AD :10156000206810B1252816D10BE000BF012000F043
:1015700000BF074960680968081A642801D2002082 :1015700019F800BF0A480068606000BF252020609D
:1015800038BD00BFEAE70020206000900320F7E7A5 :1015800000BF074960680968081A642801D2002072
:101590004400002010B5044614B1012C0AD104E027 :1015900038BD00BFEAE70020206000900320F7E795
:1015A00001210648FEF7EAFF05E002210348FEF7A5 :1015A0005800002010B5044614B1012C0AD104E003
:1015B000E5FF00E000BF00BF10BD000000100240CA :1015B00001210648FEF7ECFF05E002210348FEF793
:1015C00008B54FF48040444909680143424A11601C :1015C000E7FF00E000BF00BF10BD000000100240B8
:1015D000114609680140009100BF00BF8003111F40 :1015D00008B54FF48040444909680143424A11600C
:1015E00009680143121F116011460968014000910A :1015E000114609680140009100BF00BF8003111F30
:1015F00000BF00BF03200246384B19684FF6FF03B7 :1015F00009680143121F11601146096801400091FA
:101600001940374B0B4343EA0221344B196000BFAA :1016000000BF00BF03200246384B19684FF6FF03A6
:10161000011F1B68C3F302200F2400250346C3F1FA :101610001940374B0B4343EA0221344B196000BF9A
:10162000070CBCF1040F02D94FF0040C01E0C3F128 :10162000011F1B68C3F302200F2400250346C3F1EA
:10163000070C674603F1040CBCF1070F02D24FF010 :10163000070CBCF1040F02D94FF0040C01E0C3F118
:10164000000C01E0A3F1030C66464FF0010C0CFA0C :10164000070C674603F1040CBCF1070F02D24FF000
:1016500007FCACF1010C0CEA040C0CFA06FC4FF090 :10165000000C01E0A3F1030C66464FF0010C0CFAFC
:10166000010808FA06F8A8F1010808EA05084CEA9A :1016600007FCACF1010C0CEA040C0CFA06FC4FF080
:10167000080200BF002904DB1007030E1948435479 :10167000010808FA06F8A8F1010808EA05084CEA8A
:1016800007E01007040E15480C3001F00F031B1F74 :10168000080200BF002904DB1007030E1948435469
:10169000C45400BFFFF706FB134800681349B0FBB2 :1016900007E01007040E15480C3001F00F031B1F64
:1016A000F1F084B22046FFF711FFFFF7B5F9FFF71D :1016A000C45400BFFFF708FB134800681349B0FBA0
:1016B0004BF9FFF75BFAFFF713F8002000F018F87A :1016B000F1F084B22046FFF711FFFFF7B7F9FFF70B
:1016C000012000F015F8FFF7BDFEFFF791FE01E0E5 :1016C0004DF9FFF75DFAFFF715F8002000F018F864
:1016D000FFF7ACFEFCE70000443802400CED00E0F0 :1016D000012000F015F8FFF7BDFEFFF791FE01E0D5
:1016E0000000FA0500E400E00000002040420F0086 :1016E000FFF7ACFEFCE70000443802400CED00E0E0
:1016F00010B504460C4951F824104A000B4951F822 :1016F0000000FA0500E400E00000002040420F0076
:101700002400002100F09EF8094951F824200749DF :1017000010B504460C4951F824104A000B4951F811
:10171000083951F82400002100F094F80121034811 :101710002400002100F09EF8094951F824200749CF
:101720000830015510BD00009C180008380000204A :10172000083951F82400002100F094F80121034801
:10173000AC1800082DE9F04704460F460025A946DD :101730000830015510BD0000F01800084C000020D2
:101740002348005D20B922481838016820468847A0 :10174000001900082DE9F04704460F460025A94678
:101750001FB94FF0FF30BDE8F0871E4850F8240055 :101750002348005D20B92248183801682046884790
:10176000B7FBF0F61B4850F82400B7FBF0F100FB84 :101760001FB94FF0FF30BDE8F0871E4850F8240045
:10177000117000B1761C184850F82400451E22E074 :10177000B7FBF0F61B4850F82400B7FBF0F100FB74
:101780001348083850F8240030F8150010B909F152 :10178000117000B1761C184850F82400451E22E064
:10179000010901E04FF00009B14513D14FF00008F5 :101790001348083850F8240030F8150010B909F142
:1017A00009E00B48083850F8240005EB080220F83F :1017A000010901E04FF00009B14513D14FF00008E5
:1017B000126008F10108B045F3D3064850F8240040 :1017B00009E00B48083850F8240005EB080220F82F
:1017C0006843C8E76D1E002DDADA4FF0FF30C2E73C :1017C000126008F10108B045F3D3064850F8240030
:1017D00040000020A41800089C18000810B501461D :1017D0006843C8E76D1E002DDADA4FF0FF30C2E72C
:1017E0000023002207E00B4850F8210030F81200D7 :1017E00054000020F8180008F018000810B5014651
:1017F00000B15B1C521C084850F821009042F2D8FE :1017F0000023002207E00B4850F8210030F81200C7
:1018000064205843044C54F82140B0FBF4F0C0B2BB :1018000000B15B1C521C084850F821009042F2D8ED
:1018100010BD0000380000209C18000870B5044678 :1018100064205843044C54F82140B0FBF4F0C0B2AB
:101820000E4631462046FFF785FF0546681C08B97D :1018200010BD00004C000020F018000870B5044600
:10183000002070BD024850F824002844F9E7000059 :101830000E4631462046FFF785FF0546681C08B96D
:101840003000002030B5034601E003F8011B141EF0 :10184000002070BD024850F824002844F9E7000049
:10185000A2F10102F9D130BD102840587088A0B81B :101850004400002030B5034601E003F8011B141ECC
:10186000000000000404040000080000000800005C :10186000A2F10102F9D130BD00BF00BF00BF00BF2F
:10187000080000000800020406080A0C0001020328 :1018700000BFBFF34F8F00BF00BF00BF0948006823
:101880000405065F6C697374006C69737420616C85 :1018800000F4E06008490843001D0649086000BFF5
:101890006C20636F6D6D616E6400000000020000DB :1018900000BF00BFBFF34F8F00BF00BF00BF00BF3E
:1018A0000002000008000000080000000010000016 :1018A00000BFFDE70CED00E00000FA0510284058ED
:1018B00000100000102840587088A0B800000000F8 :1018B0007088A0B8000000000404040000080000C4
:1018C00004040400000800000008000008000000F4 :1018C00000080000080000000800020406080A0CD6
:1018D0000800020406080A0C0001020304050600C1 :1018D000000102030405065F6C697374006C697390
:1018E00010190008000000206C000000DC0E000849 :1018E0007420616C6C20636F6D6D616E640000002C
:1018F0007C1900086C000020841C0000EC0E00081D :1018F000800C0000000A0000080000000800000042
:101900007C19000800C0012000100000EC0E000847 :101900000064000000500000102840587088A0B803
:101910000024F400000000000000000000000000AF :1019100000000000040404000008000000080000AB
:1019200000000000000000000000000000000000B7 :10192000080000000800020406080A0C0001020377
:101930000000000000000000F1160008DD1700089C :101930000405060054190008000000207050000043
:101940008000002000C001208010002080140020B2 :101940000C020008241A0008705000208095000046
:101950000000000000000000000000000000000087 :10195000000F0008043A0024F43E01170008ED17B8
:1019600000000000000000000000000083180008D4 :10196000000880500020600AFF2080B4002080CD55
:0C19700089180008C6E533B4190F000800 :10197000002001FF01FF01FF01FF01FF01FF01FF47
:1019800001FF01FF01FF01FF01FF01FF01FF01FF57
:1019900001FF01FF01FF01FF01FF01FF01FF01FF47
:1019A00001FF01FF01FF01FF01FF01FF01FF01FF37
:1019B00001FF01FF01FF01FF01FF01FF01FF01FF27
:1019C00001FF01FF01FF01FF01FF01FF01FF01FF17
:1019D00001FF01FF01FF01FF01FF01FF01FF01FF07
:1019E00001FF01FF01FF01FF01FF01FF01FF01FFF7
:1019F00001FF01FF01FF01FF01FF01FF01FF01FFE7
:101A000001FF01FF01FF01FF01FF01FF01FF01FFD6
:101A100001AD2FD7180008DD180008C6E533B42D36
:041A20000F12080099
:040000050800018965 :040000050800018965
:00000001FF :00000001FF

Binary file not shown.

Binary file not shown.

View File

@ -68,8 +68,8 @@
/* Cortex-M4 Processor Interruption and Exception Handlers */ /* Cortex-M4 Processor Interruption and Exception Handlers */
/******************************************************************************/ /******************************************************************************/
/** /**
* @brief This function handles Non maskable interrupt. * @brief This function handles Non maskable interrupt.
*/ */
void NMI_Handler(void) void NMI_Handler(void)
{ {
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE BEGIN NonMaskableInt_IRQn 0 */
@ -83,8 +83,8 @@ void NMI_Handler(void)
} }
/** /**
* @brief This function handles Hard fault interrupt. * @brief This function handles Hard fault interrupt.
*/ */
void HardFault_Handler(void) void HardFault_Handler(void)
{ {
/* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE BEGIN HardFault_IRQn 0 */
@ -98,8 +98,8 @@ void HardFault_Handler(void)
} }
/** /**
* @brief This function handles Memory management fault. * @brief This function handles Memory management fault.
*/ */
void MemManage_Handler(void) void MemManage_Handler(void)
{ {
/* USER CODE BEGIN MemoryManagement_IRQn 0 */ /* USER CODE BEGIN MemoryManagement_IRQn 0 */
@ -113,8 +113,8 @@ void MemManage_Handler(void)
} }
/** /**
* @brief This function handles Pre-fetch fault, memory access fault. * @brief This function handles Pre-fetch fault, memory access fault.
*/ */
void BusFault_Handler(void) void BusFault_Handler(void)
{ {
/* USER CODE BEGIN BusFault_IRQn 0 */ /* USER CODE BEGIN BusFault_IRQn 0 */
@ -128,8 +128,8 @@ void BusFault_Handler(void)
} }
/** /**
* @brief This function handles Undefined instruction or illegal state. * @brief This function handles Undefined instruction or illegal state.
*/ */
void UsageFault_Handler(void) void UsageFault_Handler(void)
{ {
/* USER CODE BEGIN UsageFault_IRQn 0 */ /* USER CODE BEGIN UsageFault_IRQn 0 */
@ -143,8 +143,8 @@ void UsageFault_Handler(void)
} }
/** /**
* @brief This function handles System service call via SWI instruction. * @brief This function handles System service call via SWI instruction.
*/ */
void SVC_Handler(void) void SVC_Handler(void)
{ {
/* USER CODE BEGIN SVCall_IRQn 0 */ /* USER CODE BEGIN SVCall_IRQn 0 */
@ -156,8 +156,8 @@ void SVC_Handler(void)
} }
/** /**
* @brief This function handles Debug monitor. * @brief This function handles Debug monitor.
*/ */
void DebugMon_Handler(void) void DebugMon_Handler(void)
{ {
/* USER CODE BEGIN DebugMonitor_IRQn 0 */ /* USER CODE BEGIN DebugMonitor_IRQn 0 */
@ -169,8 +169,8 @@ void DebugMon_Handler(void)
} }
/** /**
* @brief This function handles Pendable request for system service. * @brief This function handles Pendable request for system service.
*/ */
void PendSV_Handler(void) void PendSV_Handler(void)
{ {
/* USER CODE BEGIN PendSV_IRQn 0 */ /* USER CODE BEGIN PendSV_IRQn 0 */
@ -182,8 +182,8 @@ void PendSV_Handler(void)
} }
/** /**
* @brief This function handles System tick timer. * @brief This function handles System tick timer.
*/ */
void SysTick_Handler(void) void SysTick_Handler(void)
{ {
/* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE BEGIN SysTick_IRQn 0 */
@ -203,8 +203,8 @@ void SysTick_Handler(void)
/******************************************************************************/ /******************************************************************************/
/** /**
* @brief This function handles ADC1, ADC2 and ADC3 global interrupts. * @brief This function handles ADC1, ADC2 and ADC3 global interrupts.
*/ */
void ADC_IRQHandler(void) void ADC_IRQHandler(void)
{ {
/* USER CODE BEGIN ADC_IRQn 0 */ /* USER CODE BEGIN ADC_IRQn 0 */
@ -217,8 +217,8 @@ void ADC_IRQHandler(void)
} }
/** /**
* @brief This function handles TIM6 global interrupt, DAC1 and DAC2 underrun error interrupts. * @brief This function handles TIM6 global interrupt, DAC1 and DAC2 underrun error interrupts.
*/ */
void TIM6_DAC_IRQHandler(void) void TIM6_DAC_IRQHandler(void)
{ {
/* USER CODE BEGIN TIM6_DAC_IRQn 0 */ /* USER CODE BEGIN TIM6_DAC_IRQn 0 */
@ -236,8 +236,8 @@ void TIM6_DAC_IRQHandler(void)
} }
/** /**
* @brief This function handles DMA2 stream0 global interrupt. * @brief This function handles DMA2 stream0 global interrupt.
*/ */
void DMA2_Stream0_IRQHandler(void) void DMA2_Stream0_IRQHandler(void)
{ {
/* USER CODE BEGIN DMA2_Stream0_IRQn 0 */ /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */

View File

@ -44,7 +44,7 @@ void MX_TIM6_Init(void)
/* USER CODE BEGIN TIM6_Init 1 */ /* USER CODE BEGIN TIM6_Init 1 */
/* USER CODE END TIM6_Init 1 */ /* USER CODE END TIM6_Init 1 */
TIM_InitStruct.Prescaler = 16799; TIM_InitStruct.Prescaler = 8399;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 99; TIM_InitStruct.Autoreload = 99;
LL_TIM_Init(TIM6, &TIM_InitStruct); LL_TIM_Init(TIM6, &TIM_InitStruct);

View File

@ -1,30 +0,0 @@
#ifndef __S_CURVE_H
#define __S_CURVE_H
#include "lib.h"
typedef struct
{
// 起始频率
float32 f0;
// 加加速段斜率
float32 faa;
// 减减速段斜率
float32 frr;
// 加加速段时间
float32 taa;
// 匀加速段时间
float32 tua;
// 减加速段时间
float32 tra;
// 匀速段时间
float32 tuu;
// 加减速段时间
float32 tar;
// 匀减速段时间
float32 tur;
// 减减速段时间
float32 trr;
} s_curve_t;
void s_curve_table_gen(uint16_t tmin, uint16_t tmax);
#endif // __S_CURVE_H

View File

@ -1,171 +0,0 @@
#include "s_curve.h"
// s曲线加速度各段参数定义
// 起始速度
#define F0 0.0f
// 加加速度与减减速度
#define FAA 0.0f
#define FRR 0.0f
// 加速段三个时间
#define TAA 0.1f
#define TUA 0.2f
#define TRA 0.1f
// 匀速段
#define TUU 5.0f
// 减速段
#define TAR 0.1f
#define TUR 0.2f
#define TRR 0.1f
// 表格长度
#define S_CURVE_TABLE_LEN 400
int16_t s_curve_table[S_CURVE_TABLE_LEN] = {0};
static int16_t s_curve_func(s_curve_t *s, float32 t, float32 *freq, float32 *acc)
{
// 辅助常数项
float32 A, B, C, D, E, F;
// 表达式中间值
float32 f3, f4, f5;
// 加速段,匀速段,减速段时间
float32 Ta, Tu, Tr;
// 减加速与加减速段斜率
float32 fra, far;
// 起始频率与加加速频率,减减速频率
float32 f0, faa, frr;
float32 taa, tua, tra, tuu, tar, tur, trr;
// 获取参数
faa = s->faa;
frr = s->frr;
taa = s->taa;
tua = s->tua;
tra = s->tra;
tuu = s->tuu;
tar = s->tar;
tur = s->tur;
trr = s->trr;
f0 = s->f0;
fra = faa * taa / tra;
far = frr * trr / tar;
Ta = taa + tua + tra;
Tu = tuu;
Tr = tar + tur + trr;
A = f0;
B = f0 - 0.5 * faa * taa * taa;
C = f0 + 0.5 * faa * taa * taa + faa * taa * tua + 0.5 * fra * (taa + tua) * (taa + tua) - fra * Ta * (taa + tua);
// f1 = f0 + 0.5 * faa * taa * taa;
// f2 = f0 + 0.5 * faa * taa * taa + faa * taa * tua;
f3 = 0.5 * fra * Ta * Ta + C;
D = f3 - 0.5 * far * (Ta + Tu) * (Ta + Tu);
f4 = -far * 0.5 * (Ta + Tu + tar) * (Ta + Tu + tar) + far * (Ta + Tu) * (Ta + Tu + tar) + D;
E = f4 + far * tar * (Ta + Tu + tar);
f5 = -far * tar * (Ta + Tu + Tr - trr) + E;
F = f5 + frr * (Ta + Tu + Tr) * (Ta + Tu + Tr - trr) - 0.5 * frr * (Ta + Tu + Tr - trr) * (Ta + Tu + Tr - trr);
// 如果时间点在全行程规定的时间段内
if ((t >= 0) && (t <= Ta + Tu + Tr))
{
// 加加速段
if ((t >= 0) && (t <= taa))
{
*freq = 0.5 * faa * t * t + A;
*acc = faa * t;
}
// 匀加速段
else if ((t >= taa) && (t <= taa + tua))
{
*freq = faa * taa * t + B;
*acc = faa * taa;
}
// 加减速段
else if ((t >= taa + tua) && (t <= taa + tua + tra))
{
*freq = -0.5 * fra * t * t + fra * Ta * t + C;
*acc = -fra * t + fra * Ta;
}
// 匀速段
else if ((t >= Ta) && (t <= Ta + tuu))
{
*freq = f3;
*acc = 0;
}
// 加减速段
else if ((t >= Ta + Tu) && (t <= Ta + Tu + tar))
{
*freq = -0.5 * far * t * t + far * (Ta + Tu) * t + D;
*acc = -far * t + far * (Ta + Tu);
}
// 匀减速
else if ((t >= Ta + Tu + tar) && (t <= Ta + Tu + tar + tur))
{
*freq = -far * tar * t + E;
*acc = -far * tar;
}
// 减减速
else if ((t >= Ta + Tu + Tr - trr) && (t <= Ta + Tu + Tr))
{
*freq = 0.5 * frr * t * t - frr * (Ta + Tu + Tr) * t + F;
*acc = frr * t - frr * (Ta + Tu + Tr);
}
}
else
{
return -1;
}
return 0;
}
// S型曲线初始化
void s_curve_table_gen(uint16_t tmin, uint16_t tmax)
{
uint16_t i, tint;
float32 ti;
float32 freq;
float32 acc;
float32 fi;
s_curve_t s;
osel_memset((uint8_t *)&s, 0, sizeof(s_curve_t));
s.f0 = F0;
s.taa = TAA;
s.tua = TUA;
s.tra = TRA;
s.tuu = TUU;
s.tar = TAR;
s.tur = TUR;
s.trr = TRR;
// 根据约束条件求出加加速段与减减速段斜率
s.faa = 2.0 / (s.taa * (s.taa + s.tra + 2 * s.tua));
s.frr = 2.0 / (s.trr * (s.tar + s.trr + 2 * s.tur));
for (i = 0; i < S_CURVE_TABLE_LEN; i++)
{
// 求出每个时间点对应的频率以及加速度
fi = i * (TAA + TUA + TRA + TUU + TAR + TUR + TRR) / S_CURVE_TABLE_LEN;
s_curve_func(&s, fi, &freq, &acc);
// 根据最大与最小装载值确定定时器实际值
ti = tmax - (tmax - tmin) * freq;
// 转换为整数值
tint = (uint16_t)ti;
// 存入s曲线表
s_curve_table[i] = tint;
}
}

View File

@ -1,737 +0,0 @@
/**
* @file ssd1306_oled.c
* @author xushenghao
* @brief SSD1306 OLED display driver
* @version 0.1
* @note PB13-SCK PB12-SDA
*/
#include "ssd1306_oled.h"
#include "ssd1306_oled.h"
/************************************6*8的点阵************************************/
const uint8_t F6x8[][6] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
};
/****************************************8*16的点阵************************************/
const uint8_t F8X16[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00, //! 1
0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //" 2
0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00, 0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00, // # 3
0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00, 0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00, //$ 4
0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00, 0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00, //% 5
0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10, //& 6
0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //' 7
0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00, //( 8
0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00, //) 9
0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00, 0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00, //* 10
0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00, //+ 11
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, //, 12
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //- 13
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, //. 14
0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04, 0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00, /// 15
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00, // 0 16
0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // 1 17
0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00, // 2 18
0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00, 0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // 3 19
0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00, // 4 20
0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00, 0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00, // 5 21
0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // 6 22
0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // 7 23
0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00, // 8 24
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00, // 9 25
0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, //: 26
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, //; 27
0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, //< 28
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, //= 29
0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, //> 30
0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00, //? 31
0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00, 0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00, //@ 32
0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20, // A 33
0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00, // B 34
0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // C 35
0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // D 36
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00, // E 37
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, // F 38
0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00, // G 39
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20, // H 40
0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // I 41
0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00, // J 42
0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00, 0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00, // K 43
0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00, // L 44
0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00, 0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00, // M 45
0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00, // N 46
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00, // O 47
0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00, // P 48
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00, // Q 49
0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20, // R 50
0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00, // S 51
0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // T 52
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // U 53
0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00, // V 54
0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00, 0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00, // W 55
0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08, 0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20, // X 56
0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00, // Y 57
0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00, // Z 58
0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00, //[ 59
0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00, //\ 60
0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, //] 61
0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //^ 62
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, //_ 63
0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //` 64
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20, // a 65
0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00, // b 66
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00, // c 67
0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20, // d 68
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00, // e 69
0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // f 70
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00, // g 71
0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // h 72
0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // i 73
0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, // j 74
0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00, // k 75
0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00, // l 76
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F, // m 77
0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20, // n 78
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00, // o 79
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00, // p 80
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80, // q 81
0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00, // r 82
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00, // s 83
0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00, // t 84
0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20, // u 85
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00, // v 86
0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, 0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00, // w 87
0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00, // x 88
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00, // y 89
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00, // z 90
0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40, //{ 91
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, //| 92
0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, //} 93
0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //~ 94
};
static uint8_t _buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8]; // 定义屏幕缓冲区
static void i2c_start(void)
{
SDA_OUT();
GPIO_SET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(4);
GPIO_RESET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
delay_us(4);
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
}
static void i2c_stop(void)
{
SDA_OUT();
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
GPIO_RESET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
delay_us(4);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
GPIO_SET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
delay_us(4);
}
static BOOL i2c_wait_ack(void)
{
uint8_t count = 0;
SDA_IN();
GPIO_SET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
delay_us(4);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(4);
while (GPIO_READ(SSD1306_SDA_PORT, SSD1306_SDA_PIN))
{
count++;
if (count > 250)
{
i2c_stop();
return FALSE;
}
}
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
return TRUE;
}
static void i2c_ack(void)
{
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
SDA_OUT();
GPIO_RESET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
delay_us(2);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(2);
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
}
static void i2c_nack(void)
{
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
SDA_OUT();
GPIO_SET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
delay_us(2);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(2);
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
}
uint8_t i2c_read_byte(BOOL ack)
{
uint8_t i = 0, receive = 0;
SDA_IN();
for (i = 0; i < 8; i++)
{
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(2);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
receive <<= 1;
if (GPIO_READ(SSD1306_SDA_PORT, SSD1306_SDA_PIN))
{
receive++;
}
delay_us(1);
}
if (!ack)
{
i2c_nack();
}
else
{
i2c_ack();
}
return receive;
}
void i2c_write_byte(uint8_t data)
{
uint8_t i = 0;
SDA_OUT();
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
for (i = 0; i < 8; i++)
{
// IIC_SDA=(txd&0x80)>>7;
if ((data & 0x80) >> 7)
GPIO_SET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
else
GPIO_RESET(SSD1306_SDA_PORT, SSD1306_SDA_PIN);
data <<= 1;
delay_us(2);
GPIO_SET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(2);
GPIO_RESET(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
delay_us(2);
}
}
static void i2c_write_command(uint8_t command)
{
uint8_t dd[2];
dd[0] = SSD1306_CMD_SET_LOW_COLUMN; // Co = 0, D/C# = 0
dd[1] = command;
i2c_start();
i2c_write_byte(SSD1306_I2C_ADDRESS);
i2c_wait_ack();
i2c_write_byte(dd[0]);
i2c_wait_ack();
i2c_write_byte(dd[1]);
i2c_wait_ack();
i2c_stop();
}
static void i2c_write_data(uint8_t data)
{
uint8_t dd[2];
dd[0] = SSD1306_CMD_SET_START_LINE; // Co = 0, D/C# = 1
dd[1] = data;
i2c_start();
i2c_write_byte(SSD1306_I2C_ADDRESS);
i2c_wait_ack();
i2c_write_byte(dd[0]);
i2c_wait_ack();
i2c_write_byte(dd[1]);
i2c_wait_ack();
}
/**
* @brief SSD1306 OLED显示屏上的显示位置
*
* SSD1306 OLED显示屏上的显示位置x和y坐标确定显示位置
*
* @param x 0-127
* @param y 0-7SSD1306 OLED的8个页面
*/
void set_position(uint8_t x, uint8_t y)
{
i2c_write_command(0xb0 + y);
i2c_write_command(((x & 0xf0) >> 4) | 0x10);
i2c_write_command((x & 0x0f) | 0x01);
}
void ssd1306_test(void)
{
ssd1306_f8x16_string(0, 0, " TEST");
ssd1306_f8x16_number(40, 0, -15.26, 2);
ssd1306_f6x8_string_number(0, 3, " @ADC1:", 'V', 24);
ssd1306_update_screen();
}
void ssd1306_init(void)
{
i2c_write_command(SSD1306_CMD_DISPLAY_OFF); // display off
i2c_write_command(SSD1306_CMD_MEMORY_MODE); // Set Memory Addressing Mode
i2c_write_command(SSD1306_CMD_SET_HIGH_COLUMN); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
i2c_write_command(SSD1306_CMD_COM_SCAN_DEC); // Set COM Output Scan Direction
i2c_write_command(SSD1306_CMD_SET_LOW_COLUMN); //---set low column address
i2c_write_command(SSD1306_CMD_SET_HIGH_COLUMN); //---set high column address
i2c_write_command(SSD1306_CMD_SET_START_LINE); //--set start line address
i2c_write_command(SSD1306_CMD_SET_CONTRAST); //--set contrast control register
i2c_write_command(0xff); // 亮度调节 0x00~0xff
i2c_write_command(0xa1); //--set segment re-map 0 to 127
i2c_write_command(SSD1306_CMD_NORMAL_DISPLAY); //--set normal display
i2c_write_command(SSD1306_CMD_SET_MULTIPLEX); //--set multiplex ratio(1 to 64)
i2c_write_command(0x3f); //
i2c_write_command(SSD1306_CMD_DISPLAY_ALL_ON_RESUME); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
i2c_write_command(SSD1306_CMD_SET_DISPLAY_OFFSET); //-set display offset
i2c_write_command(SSD1306_CMD_SET_LOW_COLUMN); //-not offset
i2c_write_command(SSD1306_CMD_SET_DISPLAY_CLOCK_DIV); //--set display clock divide ratio/oscillator frequency
i2c_write_command(0xf0); //--set divide ratio
i2c_write_command(SSD1306_CMD_SET_PRECHARGE); //--set pre-charge period
i2c_write_command(SSD1306_CMD_PAGE_ADDR); //
i2c_write_command(SSD1306_CMD_SET_COM_PINS); //--set com pins hardware configuration
i2c_write_command(0x12);
i2c_write_command(SSD1306_CMD_SET_VCOM_DETECT); //--set vcomh
i2c_write_command(SSD1306_CMD_MEMORY_MODE); // 0x20,0.77xVcc
i2c_write_command(SSD1306_CMD_CHARGE_PUMP); //--set DC-DC enable
i2c_write_command(SSD1306_CMD_SET_DC_DC_ENABLE); //
i2c_write_command(SSD1306_CMD_DISPLAY_ON); //--turn on oled panel
ssd1306_fill(0);
// ssd1306_test();
}
void ssd1306_display_on(void)
{
i2c_write_command(SSD1306_CMD_CHARGE_PUMP); // 设置电荷泵
i2c_write_command(SSD1306_CMD_SET_DC_DC_ENABLE); // 开启电荷泵
i2c_write_command(SSD1306_CMD_DISPLAY_ON); // OLED唤醒
}
void ssd1306_display_off(void)
{
i2c_write_command(SSD1306_CMD_CHARGE_PUMP); // 设置电荷泵
i2c_write_command(SSD1306_CMD_SET_HIGH_COLUMN); // 关闭电荷泵
i2c_write_command(SSD1306_CMD_DISPLAY_OFF); // OLED休眠
}
/**
* @brief SSD1306 OLED显示屏的内容
*
* SSD1306 OLED显示屏
*
*
*
* @note
*/
void ssd1306_update_screen(void)
{
for (uint8_t i = 0; i < SSD1306_HEIGHT / 8; i++)
{
i2c_write_command(0xb0 + i);
i2c_write_command(0x01);
i2c_write_command(0x10);
for (uint8_t j = 0; j < SSD1306_WIDTH; j++)
{
i2c_write_data(_buffer[j + i * SSD1306_WIDTH]);
}
}
}
/**
* @brief
*
* SSD1306 OLED
*
* @param color 0x00 0xFF
*/
void ssd1306_fill(uint8_t color)
{
osel_memset(_buffer, color, ARRAY_LEN(_buffer));
ssd1306_update_screen();
}
/**
* @brief SSD1306显示屏
*
* SSD1306显示屏发送一系列命令来清空显示内容
*
* SSD1306显示屏有8个页面
*
* 1. 0xb0 + yy为当前页面索引
* 2. 0x01
* 3. 0x10
* 4. SSD1306显示屏的宽度
* 0x00
*/
void ssd1306_clear(void)
{
osel_memset(_buffer, 0, ARRAY_LEN(_buffer));
ssd1306_update_screen();
}
void ssd1306_clear_buffer(void)
{
osel_memset(_buffer, 0, ARRAY_LEN(_buffer));
}
/**
* @brief BMP
*
* BMP使SSD1306 OLED显示屏
* ssd1306_draw_bmp(0, 0, SSD1306_WIDTH, 2);
* @param x0 BMP绘制的起始X坐标
* @param y0 BMP绘制的起始Y坐标
* @param x1 BMP绘制的结束X坐标
* @param y1 BMP绘制的结束Y坐标
*/
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *bmp)
{
uint8_t j = 0;
uint8_t x, y;
osel_memset(_buffer, 0, ARRAY_LEN(_buffer));
if (y1 % 8 == 0)
y = y1 / 8;
else
y = y1 / 8 + 1;
for (y = y0; y < y1; y++)
{
set_position(x0, y);
for (x = x0; x < x1; x++)
{
i2c_write_data(bmp[j++]);
}
}
}
/**
* @brief SSD1306 OLED显示屏上显示字符串
*
* SSD1306 OLED显示屏上以6x8像素的字体显示给定的字符串
*
* @param x x坐标
* @param y y坐标
* @param str
*/
void ssd1306_f6x8_string(uint8_t x, uint8_t y, const uint8_t *ch)
{
uint8_t c = 0, i = 0, j = 0;
while (ch[j] != '\0')
{
c = ch[j] - 32;
if (x > 126)
{
x = 0;
y++;
}
for (i = 0; i < 6; i++)
_buffer[(y * SSD1306_WIDTH) + x + i] = F6x8[c][i];
x += 6;
j++;
}
}
/**
* @brief SSD1306 OLED屏幕上显示字符串和数字
*
* SSD1306 OLED屏幕上显示字符串和数字
*
*
* @param x x坐标
* @param y y坐标
* @param ch
* @param unit 'm'
* @param num
*/
void ssd1306_f6x8_string_number(uint8_t x, uint8_t y, const uint8_t *ch, uint8_t unit, float32 num)
{
uint8_t c = 0, i = 0, j = 0;
int8_t a, number[7] = {0, 0, 0, -2, 0, 0, 0};
uint32_t d;
while (ch[j] != '\0')
{
c = ch[j] - 32;
if (x > 126)
{
x = 0;
y++;
}
for (i = 0; i < 6; i++)
_buffer[(y * SSD1306_WIDTH) + x + i] = F6x8[c][i];
x += 6;
j++;
}
d = 1000 * num;
for (a = 0; a < 3; a++)
{
number[6 - a] = d % 10;
d = d / 10;
}
for (a = 4; a < 7; a++)
{
number[6 - a] = d % 10;
d = d / 10;
}
if (num >= 100)
{
a = 0;
}
else if (num >= 10)
{
a = 1;
}
else if (num >= 0)
{
a = 2;
}
for (; a < 7; a++)
{
c = number[a] + 16;
if (x > 126)
{
x = 0;
y++;
}
for (i = 0; i < 6; i++)
_buffer[(y * SSD1306_WIDTH) + x + i] = F6x8[c][i];
x += 6;
j++;
}
for (int h = 0; h < 7; h++)
{
c = unit - 32;
for (i = 0; i < 6; i++)
_buffer[(y * SSD1306_WIDTH) + x + i] = F6x8[c][i];
}
}
/**
* @brief SSD1306 OLED显示屏上显示8x16大小的字符串
*
* 使8x16字体在SSD1306 OLED显示屏上显示指定的字符串x和y参数指定
*
* @param x x坐标
* @param y y坐标
* @param str
*/
void ssd1306_f8x16_string(uint8_t x, uint8_t y, const uint8_t *ch)
{
uint8_t c = 0, i = 0, j = 0;
while (ch[j] != '\0')
{
c = ch[j] - 32;
if (x > 120)
{
x = 0;
y++;
}
for (i = 0; i < 8; i++)
_buffer[(y * SSD1306_WIDTH) + x + i] = F8X16[c * 16 + i];
for (i = 0; i < 8; i++)
_buffer[((y + 1) * SSD1306_WIDTH) + x + i] = F8X16[c * 16 + i + 8];
x += 8;
j++;
}
}
/**
* @brief SSD1306 OLED显示屏上以8x16像素字体显示浮点数
*
* (x, y) 使8x16像素大小的字体显示浮点数 num dot_num
*
* @param x x坐标
* @param y y坐标
* @param num
* @param dot_num
*/
void ssd1306_f8x16_number(uint8_t x, uint8_t y, float32 num, uint8_t dot_num)
{
uint8_t ch[9] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
uint8_t c = 0, i = 0, j = 0;
if (num < 0)
{
ch[i++] = '-';
num = -num;
}
if (num > 32000)
return;
c = 8 - i;
if (num >= 10000)
{
ch[i++] = num / 10000 + 48;
ch[i++] = (int32_t)(num) % 10000 / 1000 + 48;
ch[i++] = (int32_t)(num) % 1000 / 100 + 48;
ch[i++] = (int32_t)(num) % 100 / 10 + 48;
ch[i++] = (int32_t)(num) % 10 + 48;
}
else if (num >= 1000)
{
ch[i++] = (int32_t)(num) % 10000 / 1000 + 48;
ch[i++] = (int32_t)(num) % 1000 / 100 + 48;
ch[i++] = (int32_t)(num) % 100 / 10 + 48;
ch[i++] = (int32_t)(num) % 10 + 48;
}
else if (num >= 100)
{
ch[i++] = (int32_t)(num) % 1000 / 100 + 48;
ch[i++] = (int32_t)(num) % 100 / 10 + 48;
ch[i++] = (int32_t)(num) % 10 + 48;
}
else if (num >= 10)
{
ch[i++] = (int32_t)(num) % 100 / 10 + 48;
ch[i++] = (int32_t)(num) % 10 + 48;
}
else if (num >= 0)
{
ch[i++] = (int32_t)(num) % 10 + 48;
}
if (dot_num > 0 && i < 7)
{
ch[i++] = '.';
num = num - (int32_t)num;
if (dot_num == 1 && i < 8)
{
num = num * 10;
ch[i++] = (int32_t)(num + 0.5) % 10 + 48;
}
if (dot_num >= 2 && i < 8)
{
num = num * 100;
ch[i++] = (int32_t)num % 100 / 10 + 48;
if (i < 8)
ch[i++] = (int32_t)(num + 0.5) % 10 + 48;
}
}
while (ch[j] != '\0')
{
c = ch[j] - 32;
if (x > 120)
{
x = 0;
y++;
}
for (i = 0; i < 8; i++)
_buffer[(y * SSD1306_WIDTH) + x + i] = F8X16[c * 16 + i];
for (i = 0; i < 8; i++)
_buffer[((y + 1) * SSD1306_WIDTH) + x + i] = F8X16[c * 16 + i + 8];
x += 8;
j++;
}
}

View File

@ -1,68 +0,0 @@
#ifndef __SSD1306_OLED_H
#define __SSD1306_OLED_H
#include "main.h"
// OLED引脚定义
#define SSD1306_SDA_PORT OLED_SDA_GPIO_Port
#define SSD1306_SDA_PIN OLED_SDA_Pin
#define SSD1306_SCK_PORT OLDE_SCK_GPIO_Port
#define SSD1306_SCK_PIN OLDE_SCK_Pin
// I2C地址
#define SSD1306_I2C_ADDRESS 0x78
// OLED显示参数
#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
// OLED命令定义
#define SSD1306_CMD_DISPLAY_OFF 0xAE
#define SSD1306_CMD_DISPLAY_ON 0xAF
#define SSD1306_CMD_SET_CONTRAST 0x81
#define SSD1306_CMD_DISPLAY_ALL_ON_RESUME 0xA4
#define SSD1306_CMD_DISPLAY_ALL_ON 0xA5
#define SSD1306_CMD_NORMAL_DISPLAY 0xA6
#define SSD1306_CMD_INVERT_DISPLAY 0xA7
#define SSD1306_CMD_SET_DISPLAY_OFFSET 0xD3
#define SSD1306_CMD_SET_COM_PINS 0xDA
#define SSD1306_CMD_SET_VCOM_DETECT 0xDB
#define SSD1306_CMD_SET_DISPLAY_CLOCK_DIV 0xD5
#define SSD1306_CMD_SET_PRECHARGE 0xD9
#define SSD1306_CMD_SET_MULTIPLEX 0xA8
#define SSD1306_CMD_SET_LOW_COLUMN 0x00
#define SSD1306_CMD_SET_HIGH_COLUMN 0x10
#define SSD1306_CMD_SET_START_LINE 0x40
#define SSD1306_CMD_MEMORY_MODE 0x20
#define SSD1306_CMD_COLUMN_ADDR 0x21
#define SSD1306_CMD_PAGE_ADDR 0x22
#define SSD1306_CMD_COM_SCAN_INC 0xC0
#define SSD1306_CMD_COM_SCAN_DEC 0xC8
#define SSD1306_CMD_SEG_REMAP 0xA0
#define SSD1306_CMD_CHARGE_PUMP 0x8D
#define SSD1306_CMD_SET_DC_DC_ENABLE 0x14
#define SDA_OUT() \
{ \
GPIO_SET_OUTPUT(SSD1306_SDA_PORT, SSD1306_SDA_PIN); \
}
#define SDA_IN() \
{ \
GPIO_SET_INPUT(SSD1306_SDA_PORT, SSD1306_SDA_PIN); \
}
// 函数声明
void ssd1306_init(void);
void ssd1306_display_on(void);
void ssd1306_display_off(void);
void ssd1306_update_screen(void);
void ssd1306_fill(uint8_t color);
void ssd1306_clear(void);
void ssd1306_clear_buffer(void);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *bmp);
void ssd1306_f6x8_string(uint8_t x, uint8_t y, const uint8_t *ch);
void ssd1306_f6x8_string_number(uint8_t x, uint8_t y, const uint8_t *ch, uint8_t unit, float32 num);
void ssd1306_f8x16_string(uint8_t x, uint8_t y, const uint8_t *ch);
void ssd1306_f8x16_number(uint8_t x, uint8_t y, float32 num, uint8_t dot_num);
#endif // __SSD1306_OLED_H

View File

@ -8,8 +8,8 @@
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"externalConsole": true, "externalConsole": true,
"cwd": "e:/work/stm32/epm/User/lib/flow", "cwd": "e:/work/stm32/study/motor_cs103/User/system/lib/driver",
"program": "e:/work/stm32/epm/User/lib/flow/build/Debug/outDebug", "program": "e:/work/stm32/study/motor_cs103/User/system/lib/driver/build/Debug/outDebug",
"MIMode": "gdb", "MIMode": "gdb",
"miDebuggerPath": "gdb", "miDebuggerPath": "gdb",
"setupCommands": [ "setupCommands": [

View File

@ -4,7 +4,7 @@
"C_Cpp_Runner.debuggerPath": "gdb", "C_Cpp_Runner.debuggerPath": "gdb",
"C_Cpp_Runner.cStandard": "", "C_Cpp_Runner.cStandard": "",
"C_Cpp_Runner.cppStandard": "", "C_Cpp_Runner.cppStandard": "",
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvarsall.bat", "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
"C_Cpp_Runner.useMsvc": false, "C_Cpp_Runner.useMsvc": false,
"C_Cpp_Runner.warnings": [ "C_Cpp_Runner.warnings": [
"-Wall", "-Wall",
@ -54,5 +54,7 @@
"C_Cpp_Runner.useUndefinedSanitizer": false, "C_Cpp_Runner.useUndefinedSanitizer": false,
"C_Cpp_Runner.useLeakSanitizer": false, "C_Cpp_Runner.useLeakSanitizer": false,
"C_Cpp_Runner.showCompilationTime": false, "C_Cpp_Runner.showCompilationTime": false,
"C_Cpp_Runner.useLinkTimeOptimization": false "C_Cpp_Runner.useLinkTimeOptimization": false,
"C_Cpp_Runner.msvcSecureNoWarnings": false,
"C_Cpp.errorSquiggles": "disabled"
} }

View File

@ -65,27 +65,27 @@ void pvd_irq_handle(void)
*/ */
void disable_debug_interface(void) void disable_debug_interface(void)
{ {
// // 使能 SYSCFG 时钟 // // 使能 SYSCFG 时钟
// LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
// // 关闭调试接口 // // 关闭调试接口
// LL_DBGMCU_DisableDBGStopMode(); // LL_DBGMCU_DisableDBGStopMode();
// LL_DBGMCU_DisableDBGStandbyMode(); // LL_DBGMCU_DisableDBGStandbyMode();
// LL_DBGMCU_DisableDBGSleepMode(); // LL_DBGMCU_DisableDBGSleepMode();
// // 关闭 SWD 和 JTAG 接口 // // 关闭 SWD 和 JTAG 接口
// LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; // LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
// // 配置 SWDIO (PA13) 和 SWCLK (PA14) 引脚为普通 GPIO // // 配置 SWDIO (PA13) 和 SWCLK (PA14) 引脚为普通 GPIO
// GPIO_InitStruct.Pin = LL_GPIO_PIN_13 | LL_GPIO_PIN_14; // GPIO_InitStruct.Pin = LL_GPIO_PIN_13 | LL_GPIO_PIN_14;
// GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; // GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
// GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; // GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
// LL_GPIO_Init(GPIOA, &GPIO_InitStruct); // LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// // 如果使用的是 JTAG 接口,还需要配置 JTDI (PA15), JTDO (PB3), 和 NJTRST (PB4) 引脚 // // 如果使用的是 JTAG 接口,还需要配置 JTDI (PA15), JTDO (PB3), 和 NJTRST (PB4) 引脚
// GPIO_InitStruct.Pin = LL_GPIO_PIN_15; // GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
// LL_GPIO_Init(GPIOA, &GPIO_InitStruct); // LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LL_GPIO_PIN_3 | LL_GPIO_PIN_4; // GPIO_InitStruct.Pin = LL_GPIO_PIN_3 | LL_GPIO_PIN_4;
// LL_GPIO_Init(GPIOB, &GPIO_InitStruct); // LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
} }

View File

@ -11,14 +11,14 @@
*/ */
#ifndef __BSP_H__ #ifndef __BSP_H__
#define __BSP_H__ #define __BSP_H__
#include "dma.h"
#include "gpios.h" #include "gpios.h"
#include "adcs.h" #include "adcs.h"
// #include "dacs.h" // #include "dacs.h"
// #include "dmas.h"
#include "tims.h" #include "tims.h"
// #include "pwms.h" // #include "pwms.h"
// #include "uarts.h" #include "uarts.h"
// #include "eeprom.h" // #include "eeprom.h"
// #include "spis.h" // #include "spis.h"
// #include "i2cs.h" // #include "i2cs.h"
@ -29,4 +29,5 @@ typedef void (*pvd_irq_handle_cb)(void);
extern void pvd_configuration(uint32_t pwr_level, pvd_irq_handle_cb call); ///< Configures the Programmable Voltage Detector (PVD) module extern void pvd_configuration(uint32_t pwr_level, pvd_irq_handle_cb call); ///< Configures the Programmable Voltage Detector (PVD) module
extern void pvd_irq_handle(void); ///< Handles the PVD interrupt extern void pvd_irq_handle(void); ///< Handles the PVD interrupt
extern void disable_debug_interface(void); ///< Disables the debug interface extern void disable_debug_interface(void); ///< Disables the debug interface
#endif ///< __BSP_H__
#endif ///< __BSP_H__

View File

@ -1,5 +1,5 @@
#ifndef __DMAS_H__ #ifndef __DMA_H__
#define __DMAS_H__ #define __DMA_H__
/** /**
* @brief DMA传输完成标志 * @brief DMA传输完成标志
@ -132,4 +132,4 @@
} \ } \
} while (__LINE__ == -1) } while (__LINE__ == -1)
#endif // __DMAS_H__ #endif // __DMA_H__

View File

@ -44,11 +44,11 @@ static uint8_t _read(gpio_t gpio)
/** /**
* @brief GPIO对象 * @brief GPIO对象
* @param {GPIO_TypeDef} *port - GPIO寄存器指针 * @param {GPIO_TypeDef} *port - GPIO寄存器指针
* @param {uint32_t} pin - * @param {uint16_t} pin -
* @return {gpio_t *} - GPIO对象指针 * @return {gpio_t *} - GPIO对象指针
* @note: GPIO对象GPIO功能 * @note: GPIO对象GPIO功能
*/ */
gpio_t *gpio_create(GPIO_TypeDef *port, uint32_t pin) gpio_t *gpio_create(GPIO_TypeDef *port, uint16_t pin)
{ {
gpio_t *gpio = (gpio_t *)osel_mem_alloc(sizeof(gpio_t)); gpio_t *gpio = (gpio_t *)osel_mem_alloc(sizeof(gpio_t));
DBG_ASSERT(gpio != NULL __DBG_LINE); DBG_ASSERT(gpio != NULL __DBG_LINE);

View File

@ -93,7 +93,7 @@
typedef struct GPIO typedef struct GPIO
{ {
GPIO_TypeDef *port; ///< The GPIO port. GPIO_TypeDef *port; ///< The GPIO port.
uint32_t pin; ///< The GPIO pin. uint16_t pin; ///< The GPIO pin.
/** /**
* @brief Set the GPIO pin to high. * @brief Set the GPIO pin to high.
@ -132,7 +132,7 @@ typedef struct GPIO
* @param pin The GPIO pin. * @param pin The GPIO pin.
* @return The created GPIO pin. * @return The created GPIO pin.
*/ */
extern gpio_t *gpio_create(GPIO_TypeDef *port, uint32_t pin); extern gpio_t *gpio_create(GPIO_TypeDef *port, uint16_t pin);
/** /**
* @brief Free the memory allocated for a GPIO pin. * @brief Free the memory allocated for a GPIO pin.

View File

@ -1 +0,0 @@
#include "pwms.h"

View File

@ -39,9 +39,6 @@
LL_TIM_CC_DisableChannel(TIMx, CHx); \ LL_TIM_CC_DisableChannel(TIMx, CHx); \
} while (__LINE__ == -1) } while (__LINE__ == -1)
#define PWM_GET_ARR(TIMx) LL_TIM_GetAutoReload(TIMx)
#define PWM_GET_PSC(TIMx) LL_TIM_GetPrescaler(TIMx)
/** /**
* @brief Sets the PWM frequency * @brief Sets the PWM frequency
* @param TIMx: TIM instance * @param TIMx: TIM instance
@ -90,30 +87,4 @@ static inline uint32_t PWM_GET_FREQ(TIM_TypeDef *TIMx)
return SystemCoreClock / (LL_TIM_GetPrescaler(TIMx) + 1) / (LL_TIM_GetAutoReload(TIMx) + 1); return SystemCoreClock / (LL_TIM_GetPrescaler(TIMx) + 1) / (LL_TIM_GetAutoReload(TIMx) + 1);
} }
/**
* @brief PWM比较值
*
* PWM比较值
*
* @param TIMx TIM_TypeDef结构体
* @param CHx LL_TIM_CHANNEL_CH1到LL_TIM_CHANNEL_CH4
*
* @return uint16_t类型的值PWM比较值0
*/
static inline uint16_t PWM_GET_COMPARE(TIM_TypeDef *TIMx, uint32_t CHx)
{
switch (CHx)
{
case LL_TIM_CHANNEL_CH1:
return LL_TIM_OC_GetCompareCH1(TIMx);
case LL_TIM_CHANNEL_CH2:
return LL_TIM_OC_GetCompareCH2(TIMx);
case LL_TIM_CHANNEL_CH3:
return LL_TIM_OC_GetCompareCH3(TIMx);
case LL_TIM_CHANNEL_CH4:
return LL_TIM_OC_GetCompareCH4(TIMx);
default:
return 0;
}
}
#endif ///< __PWMS_H__ #endif ///< __PWMS_H__

View File

@ -19,6 +19,19 @@ Given Tclk as 84MHz, we need Tout to be 200ms or 200000us. Let's assume PSC is 8
With these calculated values, both ARR and PSC are within the range of 0 to 65535, so we can use this parameter set. With these calculated values, both ARR and PSC are within the range of 0 to 65535, so we can use this parameter set.
*/ */
#define ENABLE_TIM_COUNT(TIMx) \
do \
{ \
LL_TIM_EnableCounter(TIMx); \
} while (__LINE__ == -1);
#define RESET_TIM_COUNT(TIMx) \
do \
{ \
LL_TIM_DisableCounter(TIMx); \
LL_TIM_SetCounter(TIMx, 0); \
LL_TIM_EnableCounter(TIMx); \
} while (__LINE__ == -1);
/** /**
* @brief Enables the specified TIMx. * @brief Enables the specified TIMx.
* @param TIMx TIM instance. * @param TIMx TIM instance.
@ -112,5 +125,4 @@ With these calculated values, both ARR and PSC are within the range of 0 to 6553
* @return * @return
*/ */
#define TIM_CYCLE(TIMx) ((LL_TIM_GetAutoReload(TIMx) + 1) * 0.1) #define TIM_CYCLE(TIMx) ((LL_TIM_GetAutoReload(TIMx) + 1) * 0.1)
#endif ///< __TIMS_H__ #endif ///< __TIMS_H__

View File

@ -104,7 +104,7 @@ void uart_recv_en(uart_t *uart, BOOL rx_err_en)
LL_DMA_DisableChannel(uart->dma, uart->dma_rx_channel); LL_DMA_DisableChannel(uart->dma, uart->dma_rx_channel);
// 配置RX DMA // 配置RX DMA
LL_DMA_SetPeriphAddress(uart->dma, uart->dma_rx_channel, LL_USART_DMA_GetRegAddr(uart->huart)); LL_DMA_SetPeriphAddress(uart->dma, uart->dma_rx_channel, LL_USART_DMA_GetRegAddr(uart->huart, LL_USART_DMA_REG_DATA_RECEIVE));
LL_DMA_SetMemoryAddress(uart->dma, uart->dma_rx_channel, (uint32_t)uart->rxbuf); LL_DMA_SetMemoryAddress(uart->dma, uart->dma_rx_channel, (uint32_t)uart->rxbuf);
LL_DMA_SetDataLength(uart->dma, uart->dma_rx_channel, uart->rxsize); LL_DMA_SetDataLength(uart->dma, uart->dma_rx_channel, uart->rxsize);
LL_DMA_EnableIT_TC(uart->dma, uart->dma_rx_channel); LL_DMA_EnableIT_TC(uart->dma, uart->dma_rx_channel);
@ -113,7 +113,7 @@ void uart_recv_en(uart_t *uart, BOOL rx_err_en)
LL_USART_EnableIT_IDLE(uart->huart); LL_USART_EnableIT_IDLE(uart->huart);
// 配置TX DMA // 配置TX DMA
LL_DMA_SetPeriphAddress(uart->dma, uart->dma_tx_channel, LL_USART_DMA_GetRegAddr(uart->huart)); LL_DMA_SetPeriphAddress(uart->dma, uart->dma_tx_channel, LL_USART_DMA_GetRegAddr(uart->huart, LL_USART_DMA_REG_DATA_TRANSMIT));
// 配置内存地址 // 配置内存地址
LL_DMA_SetMemoryAddress(uart->dma, uart->dma_tx_channel, (uint32_t)uart->txbuf); LL_DMA_SetMemoryAddress(uart->dma, uart->dma_tx_channel, (uint32_t)uart->txbuf);
LL_DMA_EnableIT_TC(uart->dma, uart->dma_tx_channel); LL_DMA_EnableIT_TC(uart->dma, uart->dma_tx_channel);
@ -178,7 +178,7 @@ void uart_free(uart_t *uart)
*/ */
void uart_set_baudrate(USART_TypeDef *uart, uint32_t baudrate) void uart_set_baudrate(USART_TypeDef *uart, uint32_t baudrate)
{ {
LL_USART_SetBaudRate(uart, SystemCoreClock, LL_USART_OVERSAMPLING_16); LL_USART_SetBaudRate(uart, SystemCoreClock, LL_USART_OVERSAMPLING_16, baudrate);
} }
/** /**

View File

@ -8,7 +8,7 @@
* Copyright (c) 2023 by xxx, All Rights Reserved. * Copyright (c) 2023 by xxx, All Rights Reserved.
*/ */
#include "../inc/btn.h" #include "btn.h"
#define EVENT_CB(ev) \ #define EVENT_CB(ev) \
if (handle->cb[ev]) \ if (handle->cb[ev]) \

View File

@ -47,8 +47,8 @@ while(1) {
// 根据您的需求修改常量。 // 根据您的需求修改常量。
#define TICKS_INTERVAL 10 // 按钮扫描间隔单位ms #define TICKS_INTERVAL 10 // 按钮扫描间隔单位ms
#define DEBOUNCE_TICKS 30 / TICKS_INTERVAL // 按键去抖动时间单位ms #define DEBOUNCE_TICKS 20 / TICKS_INTERVAL // 按键去抖动时间单位ms
#define SHORT_TICKS (30 / TICKS_INTERVAL) // 短按时间阈值单位ms #define SHORT_TICKS (100 / TICKS_INTERVAL) // 短按时间阈值单位ms
#define LONG_TICKS (500 / TICKS_INTERVAL) // 长按时间阈值单位ms #define LONG_TICKS (500 / TICKS_INTERVAL) // 长按时间阈值单位ms
typedef void (*BtnCallback)(void *); typedef void (*BtnCallback)(void *);

View File

@ -9,6 +9,7 @@
*/ */
#include "delay.h" #include "delay.h"
// static uint16_t g_fac_ms = 0; // ms延时倍乘数,在os下,代表每个节拍的ms数 // static uint16_t g_fac_ms = 0; // ms延时倍乘数,在os下,代表每个节拍的ms数
static uint32_t g_fac_us = 0; /* us延时倍乘数 */ static uint32_t g_fac_us = 0; /* us延时倍乘数 */
@ -79,6 +80,13 @@ void delay_us(uint32_t nus)
} }
} }
void delay_hardware_us(TIM_TypeDef *timer_us, uint32_t us)
{
RESET_TIM_COUNT(timer_us);
while (LL_TIM_GetCounter(timer_us) < us)
; // 等待计数器达到指定值
}
/** /**
* @brief nms * @brief nms
* @param nms: ms数 (0< nms <= 65535) * @param nms: ms数 (0< nms <= 65535)

23
User/system/delay.h Normal file
View File

@ -0,0 +1,23 @@
/***
* @Author:
* @Date: 2023-04-11 18:31:07
* @LastEditors: xxx
* @LastEditTime: 2023-04-11 18:31:20
* @Description:
* @email:
* @Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#ifndef __DELAY_H
#define __DELAY_H
#include "sys.h"
#include "tims.h"
void delay_init(uint16_t sysclk); /* 初始化延迟函数 */
void delay_ms(uint16_t nms); /* 延时nms */
void delay_us(uint32_t nus); /* 延时nus */
void delay_hardware_us(TIM_TypeDef *timer_us, uint32_t us); /* 硬件延时nus */
void delay_tick(uint32_t ticks); /* 延时ticks */
#endif

View File

@ -1,30 +1,34 @@
#include "dac161p997.h" #include "dac161p997.h"
#include "delay.h" #include "delay.h"
static dac161p997_t _handle; static dac161p997_t _handle;
static void _delay_us(uint32_t us)
{
delay_hardware_us(_handle.timer_us, us);
}
static void dac161p997_output_0() static void dac161p997_output_0()
{ {
_handle.io->set(*_handle.io); _handle.io->set(*_handle.io);
delay_us(DUTY_CYCLE_25); _delay_us(DUTY_CYCLE_25);
_handle.io->reset(*_handle.io); _handle.io->reset(*_handle.io);
delay_us(DUTY_CYCLE_75); _delay_us(DUTY_CYCLE_75);
} }
static void dac161p997_output_1() static void dac161p997_output_1()
{ {
_handle.io->set(*_handle.io); _handle.io->set(*_handle.io);
delay_us(DUTY_CYCLE_75); _delay_us(DUTY_CYCLE_75);
_handle.io->reset(*_handle.io); _handle.io->reset(*_handle.io);
delay_us(DUTY_CYCLE_25); _delay_us(DUTY_CYCLE_25);
} }
static void dac161p997_output_d() static void dac161p997_output_d()
{ {
_handle.io->set(*_handle.io); _handle.io->set(*_handle.io);
delay_us(DUTY_CYCLE_50); _delay_us(DUTY_CYCLE_50);
_handle.io->reset(*_handle.io); _handle.io->reset(*_handle.io);
delay_us(DUTY_CYCLE_50); _delay_us(DUTY_CYCLE_50);
} }
/** /**
@ -124,17 +128,8 @@ void dac161p997_swif_write_reg(uint16_t data, uint8_t tag)
*/ */
void dac161p997_output_current(float32 current) void dac161p997_output_current(float32 current)
{ {
uint8_t adc = (uint16_t)(current * DAC161P997_CURRENT_SLOPE) >> 8; uint16_t adc = (uint16_t)(current * DAC161P997_CURRENT_SLOPE);
static uint8_t last_adc; dac161p997_swif_write_reg(adc, DACCODE_WRITE);
if (adc == last_adc)
{
last_adc = adc;
return;
}
dac161p997_swif_write_reg(DAC161P997_LCK_REG_UNLOCK, CONFIG_WRITE);
dac161p997_swif_write_reg(DAC161P997_ERR_LOW_REG + adc, CONFIG_WRITE);
dac161p997_swif_write_reg(DAC161P997_LCK_REG_LOCK, CONFIG_WRITE);
} }
/** /**
@ -147,15 +142,13 @@ void dac161p997_output_current(float32 current)
* 2. DAC161的错误下限寄存器 * 2. DAC161的错误下限寄存器
* 3. DAC161的配置寄存器 * 3. DAC161的配置寄存器
*/ */
void dac161p997_init() void dac161p997_init(TIM_TypeDef *timer_us)
{ {
DBG_ASSERT(timer_us != NULL __DBG_LINE);
_handle.timer_us = timer_us;
ENABLE_TIM_COUNT(_handle.timer_us);
_handle.io = gpio_create(DAC161P997_IO_PORT, DAC161P997_IO_PIN); _handle.io = gpio_create(DAC161P997_IO_PORT, DAC161P997_IO_PIN);
dac161p997_swif_write_reg(DAC161P997_LCK_REG_UNLOCK, CONFIG_WRITE); dac161p997_swif_write_reg(DAC161P997_LCK_REG + DAC161P997_LCK_REG_UNLOCK, CONFIG_WRITE);
dac161p997_swif_write_reg(DAC161P997_CONFIG2_REG + dac161p997_swif_write_reg(DAC161P997_CONFIG2_REG, CONFIG_WRITE);
DAC161P997_CONFIG2_REG_LOOP + dac161p997_swif_write_reg(DAC161P997_LCK_REG + DAC161P997_LCK_REG_LOCK, CONFIG_WRITE);
DAC161P997_CONFIG2_REG_CHANNEL +
DAC161P997_CONFIG2_REG_PARITY +
DAC161P997_CONFIG2_REG_FRAME,
CONFIG_WRITE);
dac161p997_swif_write_reg(DAC161P997_LCK_REG_LOCK, CONFIG_WRITE);
} }

View File

@ -60,15 +60,16 @@
#define DACCODE_20mA (0xD555) #define DACCODE_20mA (0xD555)
#define DACCODE_24mA (0xFFFF) #define DACCODE_24mA (0xFFFF)
// cycles typedef enum
// #define QUARTER_CYCLES (625) {
// #define HALF_CYCLES (1250) DAC161P997_IDLE_SYM,
// #define THREE_CYCLES (1875)
// #define FULL_CYCLES (2500)
} dac161p997_e;
typedef struct typedef struct
{ {
TIM_TypeDef *timer_us;
gpio_t *io; gpio_t *io;
uint8_t count;
} dac161p997_t; } dac161p997_t;
void dac161p997_output_0(void); void dac161p997_output_0(void);
@ -76,6 +77,7 @@ void dac161p997_output_1(void);
void dac161p997_output_d(void); void dac161p997_output_d(void);
void dac161p997_output_symbol(uint8_t sym); void dac161p997_output_symbol(uint8_t sym);
void dac161p997_swif_write_reg(uint16_t data, uint8_t tag); void dac161p997_swif_write_reg(uint16_t data, uint8_t tag);
extern void dac161p997_output_current(float32 current); extern void dac161p997_output_current(float32 current);
extern void dac161p997_init(void); extern void dac161p997_init(TIM_TypeDef *timer_us);
#endif #endif

View File

@ -11,7 +11,20 @@
#define EEPROM_LC02B_SCL_PORT I2C1_SCL_GPIO_Port #define EEPROM_LC02B_SCL_PORT I2C1_SCL_GPIO_Port
#define EEPROM_LC02B_SCL_PIN I2C1_SCL_Pin #define EEPROM_LC02B_SCL_PIN I2C1_SCL_Pin
static i2c_t *eeprom_24lc028bt_i2c; static i2c_t *_eeprom_24lc028bt_i2c;
static TIM_TypeDef *_timer_us;
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
void eeprom_lc02b_test(void) void eeprom_lc02b_test(void)
{ {
@ -24,7 +37,7 @@ void eeprom_lc02b_test(void)
} }
eeprom_lc02b_write(test_address, buf, TEST_SIZE); eeprom_lc02b_write(test_address, buf, TEST_SIZE);
LL_mDelay(10); _delay_us(10000);
osel_memset(buf, 0, ARRAY_LEN(buf)); osel_memset(buf, 0, ARRAY_LEN(buf));
eeprom_lc02b_read(test_address, buf, TEST_SIZE); eeprom_lc02b_read(test_address, buf, TEST_SIZE);
@ -49,13 +62,19 @@ BOOL eeprom_lc02b_status_get(void)
* @return {*} * @return {*}
* @note * @note
*/ */
void eeprom_lc02b_init(void) void eeprom_lc02b_init(TIM_TypeDef *timer_us)
{ {
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios; i2c_gpio_group_t gpios;
gpios.scl = gpio_create(EEPROM_LC02B_SCL_PORT, EEPROM_LC02B_SCL_PIN); gpios.scl = gpio_create(EEPROM_LC02B_SCL_PORT, EEPROM_LC02B_SCL_PIN);
gpios.sda = gpio_create(EEPROM_LC02B_SDA_PORT, EEPROM_LC02B_SDA_PIN); gpios.sda = gpio_create(EEPROM_LC02B_SDA_PORT, EEPROM_LC02B_SDA_PIN);
eeprom_24lc028bt_i2c = i2c_create(gpios, 10); _eeprom_24lc028bt_i2c = i2c_create(gpios, 10);
// eeprom_lc02b_test(); // eeprom_lc02b_test();
} }
@ -80,37 +99,37 @@ void eeprom_lc02b_dinit(void)
void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length) void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length)
{ {
// 发送开始信号 // 发送开始信号
eeprom_24lc028bt_i2c->interface.start(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
// 发送写入地址命令 // 发送写入地址命令
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, W_ADD_COM); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
// 等待写入地址命令响应 // 等待写入地址命令响应
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 发送要写入的地址 // 发送要写入的地址
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, (uint8_t)write_addr); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)write_addr);
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 循环写入数据 // 循环写入数据
for (uint16_t i = 0; i < length; i++) for (uint16_t i = 0; i < length; i++)
{ {
// 写入一个字节数据 // 写入一个字节数据
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, *data++); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, *data++);
// 等待响应 // 等待响应
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
write_addr++; write_addr++;
if (write_addr % PAGE_SIZE == 0) if (write_addr % PAGE_SIZE == 0)
{ {
eeprom_24lc028bt_i2c->interface.stop(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
LL_mDelay(10); // 延时10ms等待写入完成 _delay_us(10000); // 延时10ms等待写入完成
eeprom_24lc028bt_i2c->interface.start(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, W_ADD_COM); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, (uint8_t)write_addr); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)write_addr);
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
} }
} }
// 写入完成停止I2C总线 // 写入完成停止I2C总线
eeprom_24lc028bt_i2c->interface.stop(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
} }
/** /**
@ -124,29 +143,29 @@ void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length)
void eeprom_lc02b_read(uint32_t read_addr, uint8_t *data, uint16_t length) void eeprom_lc02b_read(uint32_t read_addr, uint8_t *data, uint16_t length)
{ {
// 发送开始信号 // 发送开始信号
eeprom_24lc028bt_i2c->interface.start(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
// 发送写入地址命令 // 发送写入地址命令
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, W_ADD_COM); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
// 等待写入地址命令响应 // 等待写入地址命令响应
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 发送要读取的地址 // 发送要读取的地址
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, (uint8_t)read_addr); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)read_addr);
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 发送开始信号 // 发送开始信号
eeprom_24lc028bt_i2c->interface.start(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
// 发送读取地址命令 // 发送读取地址命令
eeprom_24lc028bt_i2c->interface.write_byte(eeprom_24lc028bt_i2c, R_ADD_COM); _eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, R_ADD_COM);
// 等待读取地址命令响应 // 等待读取地址命令响应
eeprom_24lc028bt_i2c->interface.wait_ack(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 循环读取数据 // 循环读取数据
for (uint16_t i = 0; i < length - 1; i++) for (uint16_t i = 0; i < length - 1; i++)
{ {
// 读取一个字节数据 // 读取一个字节数据
*data++ = eeprom_24lc028bt_i2c->interface.read_byte(eeprom_24lc028bt_i2c, TRUE); *data++ = _eeprom_24lc028bt_i2c->interface.read_byte(_eeprom_24lc028bt_i2c, TRUE);
} }
*data++ = eeprom_24lc028bt_i2c->interface.read_byte(eeprom_24lc028bt_i2c, FALSE); *data++ = _eeprom_24lc028bt_i2c->interface.read_byte(_eeprom_24lc028bt_i2c, FALSE);
// 停止I2C总线 // 停止I2C总线
eeprom_24lc028bt_i2c->interface.stop(eeprom_24lc028bt_i2c); _eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
} }

View File

@ -15,7 +15,7 @@
/** /**
* @brief Initializes the LC02B EEPROM module. * @brief Initializes the LC02B EEPROM module.
*/ */
void eeprom_lc02b_init(void); void eeprom_lc02b_init(TIM_TypeDef *timer_us);
/** /**
* @brief Deinitializes the LC02B EEPROM module. * @brief Deinitializes the LC02B EEPROM module.

View File

@ -16,6 +16,19 @@
#define RTC_RX8010_SCL_PIN RTC_SCL_Pin #define RTC_RX8010_SCL_PIN RTC_SCL_Pin
static i2c_t *rtc; static i2c_t *rtc;
static TIM_TypeDef *_timer_us;
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
/* sec, min, hour, week, day, month, year */ /* sec, min, hour, week, day, month, year */
// static uint8_t calendar[7] = {0, 0, 0, 1, 29, 2, 98}; // static uint8_t calendar[7] = {0, 0, 0, 1, 29, 2, 98};
@ -316,7 +329,7 @@ static BOOL rtc_soft_reset(void)
if (ret == 0) if (ret == 0)
{ {
LL_mDelay(2); _delay_us(2000);
} }
return ret; return ret;
@ -354,8 +367,14 @@ static BOOL rtc_clock_reginit(void)
* @return {BOOL} TRUE = FALSE = * @return {BOOL} TRUE = FALSE =
* @note * @note
*/ */
BOOL rtc_init(void) BOOL rtc_init(TIM_TypeDef *timer_us)
{ {
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios; i2c_gpio_group_t gpios;
int ret = 1; int ret = 1;
gpios.scl = gpio_create(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN); gpios.scl = gpio_create(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);

View File

@ -57,7 +57,7 @@ typedef struct
* @brief Initializes the RTC module. * @brief Initializes the RTC module.
* @return TRUE if the initialization is successful, FALSE otherwise. * @return TRUE if the initialization is successful, FALSE otherwise.
*/ */
extern BOOL rtc_init(void); extern BOOL rtc_init(TIM_TypeDef *timer_us);
/** /**
* @brief Deinitializes the RTC module. * @brief Deinitializes the RTC module.

View File

@ -1,5 +1,6 @@
#include "sht40.h" #include "sht40.h"
#include "i2cs.h" #include "i2cs.h"
#include "delay.h"
#define SHT40_SDA_PORT I2C1_SDA_GPIO_Port #define SHT40_SDA_PORT I2C1_SDA_GPIO_Port
#define SHT40_SDA_PIN I2C1_SDA_Pin #define SHT40_SDA_PIN I2C1_SDA_Pin
#define SHT40_SCL_PORT I2C1_SCL_GPIO_Port #define SHT40_SCL_PORT I2C1_SCL_GPIO_Port
@ -8,9 +9,22 @@
#define SHT40_I2C_ADDRESS 0x44 #define SHT40_I2C_ADDRESS 0x44
#define SHT40_MEASURE_CMD 0xFD // 2*8-bit T-data:8-bit CRC:2*8-bit RH-data: 8-bit CRC #define SHT40_MEASURE_CMD 0xFD // 2*8-bit T-data:8-bit CRC:2*8-bit RH-data: 8-bit CRC
static i2c_t *sht40_i2c; static i2c_t *_sht40_i2c;
static TIM_TypeDef *_timer_us;
static uint8_t crc8(uint8_t *data, uint8_t len); static uint8_t crc8(uint8_t *data, uint8_t len);
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
void sht40_test(void) void sht40_test(void)
{ {
float32 temperature = 0; float32 temperature = 0;
@ -26,14 +40,21 @@ void sht40_test(void)
* *
* sht40_i2c SHT40 * sht40_i2c SHT40
*/ */
void sht40_init(void) void sht40_init(TIM_TypeDef *timer_us)
{ {
DBG_ASSERT(timer_us != NULL __DBG_LINE);
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios; i2c_gpio_group_t gpios;
gpios.scl = gpio_create(SHT40_SCL_PORT, SHT40_SCL_PIN); gpios.scl = gpio_create(SHT40_SCL_PORT, SHT40_SCL_PIN);
gpios.sda = gpio_create(SHT40_SDA_PORT, SHT40_SDA_PIN); gpios.sda = gpio_create(SHT40_SDA_PORT, SHT40_SDA_PIN);
sht40_i2c = i2c_create(gpios, 10); _sht40_i2c = i2c_create(gpios, 10);
DBG_ASSERT(sht40_i2c != NULL __DBG_LINE); DBG_ASSERT(_sht40_i2c != NULL __DBG_LINE);
// sht40_test(); // 测试 SHT40 // sht40_test(); // 测试 SHT40
} }
@ -65,32 +86,32 @@ BOOL sht40_read(float32 *temperature, float32 *humidity)
osel_memset(data, 0, ARRAY_LEN(data)); osel_memset(data, 0, ARRAY_LEN(data));
// 发送开始信号 // 发送开始信号
sht40_i2c->interface.start(sht40_i2c); _sht40_i2c->interface.start(_sht40_i2c);
// 发送写入地址命令 // 发送写入地址命令
sht40_i2c->interface.write_byte(sht40_i2c, SHT40_I2C_ADDRESS << 1); _sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_I2C_ADDRESS << 1);
// 等待写入地址命令响应 // 等待写入地址命令响应
if (sht40_i2c->interface.wait_ack(sht40_i2c) == FALSE) if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
{ {
return FALSE; return FALSE;
} }
// 发送测量命令 // 发送测量命令
sht40_i2c->interface.write_byte(sht40_i2c, SHT40_MEASURE_CMD); _sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_MEASURE_CMD);
// 等待测量命令响应 // 等待测量命令响应
if (sht40_i2c->interface.wait_ack(sht40_i2c) == FALSE) if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
{ {
return FALSE; return FALSE;
} }
// 停止I2C总线 // 停止I2C总线
sht40_i2c->interface.stop(sht40_i2c); _sht40_i2c->interface.stop(_sht40_i2c);
LL_mDelay(10); // 根据 SHT40 数据手册,等待至少 10ms _delay_us(10000); // 根据 SHT40 数据手册,等待至少 10ms
// 发送开始信号 // 发送开始信号
sht40_i2c->interface.start(sht40_i2c); _sht40_i2c->interface.start(_sht40_i2c);
// 发送写入地址命令 // 发送写入地址命令
sht40_i2c->interface.write_byte(sht40_i2c, (SHT40_I2C_ADDRESS << 1) | 1); _sht40_i2c->interface.write_byte(_sht40_i2c, (SHT40_I2C_ADDRESS << 1) | 1);
// 等待写入地址命令响应 // 等待写入地址命令响应
if (sht40_i2c->interface.wait_ack(sht40_i2c) == FALSE) if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
{ {
return FALSE; return FALSE;
} }
@ -99,16 +120,16 @@ BOOL sht40_read(float32 *temperature, float32 *humidity)
{ {
if (i == 5) if (i == 5)
{ {
data[i] = sht40_i2c->interface.read_byte(sht40_i2c, FALSE); data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, FALSE);
} }
else else
{ {
data[i] = sht40_i2c->interface.read_byte(sht40_i2c, TRUE); data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, TRUE);
} }
} }
// 停止I2C总线 // 停止I2C总线
sht40_i2c->interface.stop(sht40_i2c); _sht40_i2c->interface.stop(_sht40_i2c);
*temperature = 0; *temperature = 0;
*humidity = 0; *humidity = 0;

View File

@ -2,7 +2,7 @@
#define __SHT40_H #define __SHT40_H
#include "main.h" #include "main.h"
void sht40_init(void); ///< 初始化 SHT40 传感器 void sht40_init(TIM_TypeDef *timer_us); ///< 初始化 SHT40 传感器
void sht40_dinit(void); ///< 反初始化 SHT40 传感器 void sht40_dinit(void); ///< 反初始化 SHT40 传感器
BOOL sht40_read(float32 *temperature, float32 *humidity); ///< 读取温湿度传感器数据 BOOL sht40_read(float32 *temperature, float32 *humidity); ///< 读取温湿度传感器数据

View File

@ -1,21 +0,0 @@
/***
* @Author:
* @Date: 2023-04-11 18:31:07
* @LastEditors: xxx
* @LastEditTime: 2023-04-11 18:31:20
* @Description:
* @email:
* @Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#ifndef __DELAY_H
#define __DELAY_H
#include "sys.h"
void delay_init(uint16_t sysclk); /* 初始化延迟函数 */
void delay_ms(uint16_t nms); /* 延时nms */
void delay_us(uint32_t nus); /* 延时nus */
void delay_tick(uint32_t ticks); /* 延时ticks */
#endif

View File

@ -0,0 +1,38 @@
#include "pid_c.h"
/**
* @brief PID控制器参数
* @param {PID_C} *self - PID控制器结构体指针
* @param {float32} kp -
* @param {float32} ki -
* @param {float32} kd -
* @param {float32} out_min -
* @param {float32} out_max -
* @return {*} -
*/
static void _set_ctrl_prm(struct PID_C *self, float32 kp, float32 ki, float32 kd, float32 out_min, float32 out_max)
{
self->pri.kp = kp; /*比例系数*/
self->pri.ki = ki; /*积分系数*/
self->pri.kd = kd; /*微分系数*/
self->pri.deadband = 0.5; /*死区*/
self->pri.maximum = out_max; /*最大输出*/
self->pri.minimum = out_min; /*最小输出*/
self->pri.last_error = 0; /*上一次误差*/
self->pri.prev_error = 0; /*上上次误差*/
}
static float32 _PID(struct PID_C *self, float32 target, float32 feedback)
{
/**
* PID算法
*/
return 0;
}
void pid_c_constructor(struct PID_C *self)
{
self->set_ctrl_prm = _set_ctrl_prm;
self->PID = _PID;
}

View File

@ -0,0 +1,34 @@
#ifndef __PID_C_H__
#define __PID_C_H__
#include "lib.h"
typedef struct PID_C
{
/* 设置PID三个参数 */
void (*set_ctrl_prm)(struct PID_C *self, float32 kp, float32 ki, float32 kd, float32 out_min, float32 out_max);
/* 控制接口 */
float32 (*PID)(struct PID_C *self, float32 target, float32 feedback);
// 自定义参数
/* 实际值与目标值之间的误差 */
float32 err;
/* 输出值 */
float32 out;
/* private */
struct
{
float32 kp; /*比例学习速度*/
float32 ki; /*积分学习速度*/
float32 kd; /*微分学习速度*/
float32 ki_error; /*积分误差*/
float32 last_error; /*前一拍偏差*/
float32 prev_error; /*前两拍偏差*/
float32 deadband; /*死区*/
float32 maximum; /*输出值的上限*/
float32 minimum; /*输出值的下限*/
} pri;
} pid_c_t;
extern void pid_c_constructor(struct PID_C *self);
#endif // __PID_C_H__

View File

@ -0,0 +1,285 @@
#include "pid_g.h"
#include <math.h>
/**
* @brief PID积分及微分控制数据
* @param {PID_G} *self
* @return {*}
*/
static void _restctrl(struct PID_G *self)
{
self->pri.pre_error = 0;
self->pri.sum_iterm = 0;
}
/**
* @brief
* @param {PID_G} *self
* @param {float32} out_min
* @param {float32} out_max
* @return {*}
* @note
*/
static void _set_range(struct PID_G *self, float32 out_min, float32 out_max)
{
self->pri.out_max = out_max;
self->pri.out_min = out_min;
}
/**
* @brief kp
* @param {PID_G} *self
* @param {float32} kp
* @return {*}
* @note
*/
static void _set_kp(struct PID_G *self, float32 kp)
{
self->pri.kp = kp;
}
/**
* @brief ki
* @param {PID_G} *self
* @param {float32} ki
* @return {*}
* @note
*/
static void _set_ki(struct PID_G *self, float32 ki)
{
self->pri.ki = ki;
}
/**
* @brief kd
* @param {PID_G} *self
* @param {float32} kd
* @return {*}
* @note
*/
static void _set_kd(struct PID_G *self, float32 kd)
{
self->pri.kd = kd;
}
/**
* @brief 使
* @param {PID_G} *self
* @param {BOOL} enable
* @return {*}
* @note
*/
static void _set_ki_enable(struct PID_G *self, BOOL enable)
{
self->pri.ki_enable = enable;
}
/**
* @brief 使
* @param {PID_G} *self
* @param {BOOL} enable
* @return {*}
* @note
*/
static void _set_kd_enable(struct PID_G *self, BOOL enable)
{
self->pri.kd_enable = enable;
}
/**
* @brief
* @return {*}
* @note
*/
static void _set_ctrl_prm(struct PID_G *self, float32 kp, float32 ki, float32 kd, float32 err_dead, float32 out_min, float32 out_max)
{
g_param_t *pri = &self->pri;
osel_memset((uint8_t *)pri, 0, sizeof(pid_g_t));
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->err_dead = err_dead;
pri->out_max = out_max;
pri->out_min = out_min;
pri->detach = FALSE;
}
static void _update_ctrl_prm(struct PID_G *self, float32 kp, float32 ki, float32 kd, float32 err_dead, float32 out_min, float32 out_max)
{
g_param_t *pri = &self->pri;
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->err_dead = err_dead;
pri->out_max = out_max;
pri->out_min = out_min;
pri->detach = FALSE;
}
/**
* @brief 0+PID,PID
* @param {PID_G} *self
* @param {float32} max_err
* @param {BOOL} mode
* @return {*}
*/
static void _set_cfg(struct PID_G *self, float32 max_err, BOOL mode)
{
self->pri.err_limit = max_err;
self->pri.detach = mode == FALSE ? FALSE : TRUE;
}
/**
* @brief
* @param {PID_G} *self
* @param {float32} max_weight
* @return {*}
* @note
*/
static void _set_weight(struct PID_G *self, float32 max_ratio, BOOL mode)
{
self->pri.ui_ratio = max_ratio;
self->pri.weight = mode == FALSE ? FALSE : TRUE;
}
/**
* @brief PID算法函数
* @param {PID_G} *self
* @param {float32} target
* @param {float32} feedback
* @return {*}
* @note
*/
static float32 _PID(struct PID_G *self, float32 target, float32 feedback)
{
float32 error = 0.0f;
float32 insert = 0.0f; ///< 该值为0时积分不介入计算
float32 temp_iterm = 0.0f;
float32 temp_kd = 0.0f;
g_param_t *pri = &self->pri;
pri->ref = target; ///< 目标位置
pri->feed_back = feedback; ///< 实际位置
pri->error = pri->ref - pri->feed_back; /// 误差
error = pri->error;
if (fabs(pri->error) <= pri->err_dead) ///< 误差小于死区,不计算
{
error = 0;
}
/*根据PID配置的模式,获取积分数据,进行积分累加*/
if (pri->out >= pri->out_max) ///< 到达输出上限
{
if (fabs(error) > pri->err_limit && pri->detach) ///< 误差大于积分介入区间,积分不介入计算
{
insert = 0;
}
else
{
insert = 1;
if (error < 0)
{
temp_iterm = pri->ki * error;
}
}
}
else if (pri->out <= pri->out_min) ///< 到达输出下限
{
if (fabs(error) > pri->err_limit && pri->detach) ///< 误差大于积分介入区间,积分不介入计算
{
insert = 0;
}
else
{
insert = 1;
if (error > 0)
{
temp_iterm = pri->ki * error;
}
}
}
else
{
if (fabs(error) > pri->err_limit && pri->detach)
{
insert = 0;
}
else
{
insert = 1;
temp_iterm = pri->ki * error;
}
}
if (pri->ki_enable == FALSE)
{
temp_iterm = 0;
insert = 0;
}
/* integral */
pri->sum_iterm += temp_iterm;
if (pri->weight == TRUE)
{
if (pri->sum_iterm > pri->ui_ratio)
{
pri->sum_iterm = pri->ui_ratio;
}
else if (pri->sum_iterm < -pri->ui_ratio)
{
pri->sum_iterm = -pri->ui_ratio;
}
}
else
{
if (pri->sum_iterm > pri->out_max)
{
pri->sum_iterm = pri->out_max;
}
else if (pri->sum_iterm < pri->out_min)
{
pri->sum_iterm = pri->out_min;
}
}
/* differential */
if (pri->kd_enable == TRUE)
{
temp_kd = pri->kd;
}
else
{
temp_kd = 0;
}
pri->out = pri->kp * pri->error + pri->sum_iterm * insert + (pri->error - pri->pre_error) * temp_kd;
pri->pre_error = pri->error; ///< 记录这次误差,为下次微分计算做准备
pri->pre_feed_back = pri->feed_back;
/*limt pid output*/
pri->out = RANGE(pri->out, pri->out_min, pri->out_max); ///< 限制输出
return pri->out;
}
/**
* @brief PID接口
* @param {PID_G} *self
* @return {*}
* @note
*/
void pid_g_constructor(struct PID_G *self)
{
self->set_ctrl_prm = _set_ctrl_prm;
self->update_ctrl_prm = _update_ctrl_prm;
self->set_cfg = _set_cfg;
self->set_kp = _set_kp;
self->set_ki_enable = _set_ki_enable;
self->set_ki = _set_ki;
self->set_kd_enable = _set_kd_enable;
self->set_kd = _set_kd;
self->set_range = _set_range;
self->restctrl = _restctrl;
self->PID = _PID;
self->set_weight = _set_weight;
}

View File

@ -0,0 +1,65 @@
#ifndef __PID_G_H__
#define __PID_G_H__
#include "lib.h"
typedef struct
{
float32 ref; /*目标*/
float32 feed_back; /*实际*/
float32 pre_feed_back; /*上一次实际*/
float32 kp; /*比例学习速度*/
float32 ki; /*积分学习速度*/
float32 kd; /*微分学习速度*/
float32 ki_error; /*积分误差*/
float32 error; /*误差*/
float32 pre_error; /*前一拍偏差*/
float32 prev_error; /*前两拍偏差*/
float32 err_dead; /*死区*/
float32 err_limit; /*积分分离上限*/
float32 maximum; /*输出值的上限*/
float32 minimum; /*输出值的下限*/
float32 out; /*输出值*/
float32 sum_iterm; /*积分累加*/
float32 ui_ratio; /*积分权重*/
BOOL ki_enable; /*积分使能*/
BOOL kd_enable; /*微分使能*/
BOOL detach; /*积分分离标志*/
BOOL weight; /*积分权重标志*/
float32 out_max; /*输出最大值*/
float32 out_min; /*输出最小值*/
} g_param_t;
typedef struct PID_G
{
/* 设置PID三个参数 */
void (*set_ctrl_prm)(struct PID_G *self, float32 kp, float32 ki, float32 kd, float32 err_dead, float32 out_min, float32 out_max);
/* 更新PID参数 */
void (*update_ctrl_prm)(struct PID_G *self, float32 kp, float32 ki, float32 kd, float32 err_dead, float32 out_min, float32 out_max);
/* 控制接口 */
float32 (*PID)(struct PID_G *self, float32 target, float32 feedback);
/* 更新控制区间 */
void (*set_range)(struct PID_G *self, float32 out_min, float32 out_max);
/* 设置积分分离 */
void (*set_cfg)(struct PID_G *self, float32 max_err, BOOL mode);
/* 设置积分权重 */
void (*set_weight)(struct PID_G *self, float32 max_ratio, BOOL mode);
/* 更新kp */
void (*set_kp)(struct PID_G *self, float32 kp);
/* 使能ki */
void (*set_ki_enable)(struct PID_G *self, BOOL enable);
/* 更新ki */
void (*set_ki)(struct PID_G *self, float32 ki);
/* 使能kd */
void (*set_kd_enable)(struct PID_G *self, BOOL enable);
/* 更新kd */
void (*set_kd)(struct PID_G *self, float32 kd);
/* 复位PID积分及微分控制数据 */
void (*restctrl)(struct PID_G *self);
/* private */
g_param_t pri;
} pid_g_t;
extern void pid_g_constructor(struct PID_G *self);
#endif // __PID_G_H__

View File

@ -0,0 +1,166 @@
#include "pid_hd.h"
#include <math.h>
#include "sys.h"
#include "app.h"
#if INCOMPLETE_DIFFEREN_HD == 1 // 积分分离
/*计算微分项,使用追随误差微分项*/
static float32 td_derivative(struct PID_HD *self, float32 current_err, float32 pre_err, float32 dt)
{
pid_hd_position_t *pri = &self->pri_u.position;
float32 derivative = (current_err - pre_err) / dt; // 计算积分项
derivative = pri->td_alpha * derivative + (1 - pri->td_alpha) * pri->td_beta * pri->pre_derivative; // 追随误差微分器平滑输出
pri->pre_derivative = derivative; // 更新上一次误差
return derivative;
}
#endif
/*杭电设置位置式PID参数*/
static void _set_ctrl_prm_position(struct PID_HD *self, float32 kp, float32 ki, float32 kd)
{
pid_hd_position_t *pri = &self->pri_u.position;
osel_memset((uint8_t *)pri, 0, sizeof(pid_hd_position_t));
/*观测传进来的Kp、Ki、Kd*/
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->ki_limit = 10; // 积分分离界限
pri->err_dead = 0.5; // 控制死区范围
#if INCOMPLETE_DIFFEREN_HD == 1
/*不完全微分系数*/
pri->td_alpha = 0.5;
pri->td_beta = 0.5;
#endif
}
/*杭电:设置输出限幅参数*/
static void _set_out_prm_position(struct PID_HD *self, float32 maximum, float32 minimum)
{
self->pri_u.position.out_max = maximum;
self->pri_u.position.out_min = minimum;
}
/*杭电位置式PID控制算法*/
static float32 _pid_position(struct PID_HD *self, float32 err)
{
/*计算控制的运行时间*/
// sys_millis_reset();
self->pri_u.position.control_time = sys_millis();
self->pri_u.position.tmp_time = 0;
/*测试4.18*/
if (fabs(err) < 0.1)
{
err = 0;
}
float32 x[3];
self->pri_u.position.err = err;
/*抗积分饱和*/
#if INTEGRAL_SEPARATION == 1 // 积分分离
if (self->pri_u.position.out > self->pri_u.position.out_max)
{
if (self->pri_u.position.err > self->pri_u.position.ki_limit) // 积分分离
{
self->pri_u.position.ki_error += 0;
}
else
{
if (self->pri_u.position.err < 0) // 若偏差为负值,执行负偏差的累加
{
self->pri_u.position.ki_error += self->pri_u.position.err;
}
}
}
else if (self->pri_u.position.out < self->pri_u.position.out_min)
{
if (self->pri_u.position.err > self->pri_u.position.ki_limit) // 若偏差为负值,停止积分
{
self->pri_u.position.ki_error += 0;
}
else
{
if (self->pri_u.position.err > 0) // 若偏差为正值,执行正偏差的累加
{
self->pri_u.position.ki_error += self->pri_u.position.err;
}
}
}
else
{
if (fabs(err) > self->pri_u.position.ki_limit || fabs(err) < 0.5)
{
self->pri_u.position.ki_error += 0;
}
else
{
self->pri_u.position.ki_error += self->pri_u.position.err;
}
}
#else /*无积分分离操作*/
if (fabs(err) < 0.4)
{
self->pri_u.position.ki_error += 0;
}
else
{
self->pri_u.position.ki_error += self->pri_u.position.err;
}
#endif
/*输出*/
if (fabs(err) < self->pri_u.position.err_dead)
{
/*输出上一次的值*/
// self->pri_u.position.out = self->pri_u.position.pre_out;
x[0] = self->pri_u.position.err;
x[1] = self->pri_u.position.ki_error;
self->pri_u.position.out = self->pri_u.position.kp * x[0] + self->pri_u.position.ki * x[1] + self->pri_u.position.kd * x[2];
}
else
{
x[0] = self->pri_u.position.err;
x[1] = self->pri_u.position.ki_error;
#if INCOMPLETE_DIFFEREN_HD == 1
/*不完全微分项为了解决普通PID为微分环节容易振荡的问题*/
self->pri_u.position.tmp_time = sys_millis();
self->pri_u.position.control_time -= self->pri_u.position.tmp_time;
self->pri_u.position.control_time /= 1000.0; // 将单位转换为秒
x[2] = td_derivative(&_pid.pid_u.hd, err, self->pri_u.position.pre_error, self->pri_u.position.control_time);
#else
// 普通的微分环节
x[2] = self->pri_u.position.err - self->pri_u.position.pre_error;
#endif
self->pri_u.position.out = self->pri_u.position.kp * x[0] + self->pri_u.position.ki * x[1] + self->pri_u.position.kd * x[2];
}
/*输出限幅*/
if (self->pri_u.position.out > self->pri_u.position.out_max)
{
self->pri_u.position.out = self->pri_u.position.out_max;
}
if (self->pri_u.position.out < self->pri_u.position.out_min)
{
self->pri_u.position.out = self->pri_u.position.out_min;
}
// 更新误差历史
self->pri_u.position.pre_error = self->pri_u.position.err; /*上一次误差值*/
// 更新输出历史
self->pri_u.position.pre_out = self->pri_u.position.out; /*上一次输出值*/
return self->pri_u.position.out;
}
/*杭电:参数控制器*/
void pid_hd_constructor(struct PID_HD *self)
{
self->set_ctrl_prm_position = _set_ctrl_prm_position;
self->set_out_prm_position = _set_out_prm_position;
self->pid_position = _pid_position;
}

View File

@ -0,0 +1,66 @@
#ifndef __PID_HD__
#define __PID_HD__
#include "lib.h"
#define INTEGRAL_SEPARATION 1 // 积分分离
#define INCOMPLETE_DIFFEREN_HD 1 // 不完全微分
typedef struct
{
float32 ref;
float32 feed_back;
float32 pre_feed_back;
float32 pre_error;
float32 ki_error; /*积分误差*/
float32 ki_limit; /*积分分离界限*/
float32 ki_alpha; /*变积分的系数*/
float32 err;
float32 sum_iterm;
float32 kp;
float32 kp_small; /*在接近稳态时的Kp*/
float32 kp_big; /*在大范围时的Kp*/
float32 ki;
float32 kd;
float32 err_limit;
BOOL detach;
float32 err_dead;
#if INCOMPLETE_DIFFEREN_HD == 1
float32 td_alpha; /*不完全微分系数*/
float32 td_beta; /*不完全微分系数beta*/
float32 pre_derivative; /*上一次微分值*/
#endif
float32 out;
float32 pre_out;
float32 out_max;
float32 out_min;
BOOL sm;
float32 sv_range;
uint32_t control_time; /*控制算法运行一次花费的时间*/
uint32_t tmp_time; /*临时用来记录控制的运行时间*/
} pid_hd_position_t; // 位置式PID
typedef struct PID_HD
{
/* 设置PID三个参数 */
void (*set_ctrl_prm_position)(struct PID_HD *self, float32 kp, float32 ki, float32 kd);
/* 设置输出范围 */
void (*set_out_prm_position)(struct PID_HD *self, float32 maximum, float32 minimum);
/* 控制接口 */
float32 (*pid_position)(struct PID_HD *self, float32 err);
// 自定义参数
/* 实际值与目标值之间的误差 */
float32 err;
/* 输出值 */
float32 out;
/* private */
struct
{
pid_hd_position_t position;
} pri_u;
} pid_hd_t;
extern void pid_hd_constructor(struct PID_HD *self);
#endif // __PID_HD__

View File

@ -0,0 +1,481 @@
#include "pid_x.h"
#include "math.h"
#define LAG_PHASE (6) // 迟滞相位,单位:拍
#ifndef PI
#define PI 3.14159265358979f
#endif
// 注1自适应模糊pid最重要的就是论域的选择要和你应该控制的对象相切合
// 注2以下各阀值、限幅值、输出值均需要根据具体的使用情况进行更改
// 注3因为我的控制对象惯性比较大所以以下各部分取值较小
// 论域e:[-5,5] ec:[-0.5,0.5]
// 误差的阀值小于这个数值的时候不做PID调整避免误差较小时频繁调节引起震荡
#define Emin 0.3f
#define Emid 1.0f
#define Emax 5.0f
// 调整值限幅,防止积分饱和
#define Umax 1
#define Umin -1
#define NB 0
#define NM 1
#define NS 2
#define ZO 3
#define PS 4
#define PM 5
#define PB 6
int32_t kp[7][7] = {{PB, PB, PM, PM, PS, ZO, ZO},
{PB, PB, PM, PS, PS, ZO, ZO},
{PM, PM, PM, PS, ZO, NS, NS},
{PM, PM, PS, ZO, NS, NM, NM},
{PS, PS, ZO, NS, NS, NM, NM},
{PS, ZO, NS, NM, NM, NM, NB},
{ZO, ZO, NM, NM, NM, NB, NB}};
int32_t kd[7][7] = {{PS, NS, NB, NB, NB, NM, PS},
{PS, NS, NB, NM, NM, NS, ZO},
{ZO, NS, NM, NM, NS, NS, ZO},
{ZO, NS, NS, NS, NS, NS, ZO},
{ZO, ZO, ZO, ZO, ZO, ZO, ZO},
{PB, NS, PS, PS, PS, PS, PB},
{PB, PM, PM, PM, PS, PS, PB}};
int32_t ki[7][7] = {{NB, NB, NM, NM, NS, ZO, ZO},
{NB, NB, NM, NS, NS, ZO, ZO},
{NB, NM, NS, NS, ZO, PS, PS},
{NM, NM, NS, ZO, PS, PM, PM},
{NM, NS, ZO, PS, PS, PM, PB},
{ZO, ZO, PS, PS, PM, PB, PB},
{ZO, ZO, PS, PM, PM, PB, PB}};
static float32 ec; // 误差变化率
/**************求隶属度(三角形)***************/
float32 FTri(float32 x, float32 a, float32 b, float32 c) // FuzzyTriangle
{
if (x <= a)
return 0;
else if ((a < x) && (x <= b))
return (x - a) / (b - a);
else if ((b < x) && (x <= c))
return (c - x) / (c - b);
else if (x > c)
return 0;
else
return 0;
}
/*****************求隶属度(梯形左)*******************/
float32 FTraL(float32 x, float32 a, float32 b) // FuzzyTrapezoidLeft
{
if (x <= a)
return 1;
else if ((a < x) && (x <= b))
return (b - x) / (b - a);
else if (x > b)
return 0;
else
return 0;
}
/*****************求隶属度(梯形右)*******************/
float32 FTraR(float32 x, float32 a, float32 b) // FuzzyTrapezoidRight
{
if (x <= a)
return 0;
if ((a < x) && (x < b))
return (x - a) / (b - a);
if (x >= b)
return 1;
else
return 1;
}
/****************三角形反模糊化处理**********************/
float32 uFTri(float32 x, float32 a, float32 b, float32 c)
{
float32 y, z;
z = (b - a) * x + a;
y = c - (c - b) * x;
return (y + z) / 2;
}
/*******************梯形(左)反模糊化***********************/
float32 uFTraL(float32 x, float32 a, float32 b)
{
return b - (b - a) * x;
}
/*******************梯形(右)反模糊化***********************/
float32 uFTraR(float32 x, float32 a, float32 b)
{
return (b - a) * x + a;
}
/**************************求交集****************************/
float32 fand(float32 a, float32 b)
{
return (a < b) ? a : b;
}
/**************************求并集****************************/
float32 forr(float32 a, float32 b)
{
return (a < b) ? b : a;
}
static float32 _PID(struct PID_X *self, float32 target, float32 feedback)
{
float32 pwm_var; // pwm调整量
float32 iError; // 当前误差
float32 set, input;
CLASSICPID *pri = &self->pri;
// 计算隶属度表
float32 es[7], ecs[7], e;
float32 form[7][7];
int i = 0, j = 0;
int MaxX = 0, MaxY = 0;
// 记录隶属度最大项及相应推理表的p、i、d值
float32 lsd;
int temp_p, temp_d, temp_i;
float32 detkp, detkd, detki; // 推理后的结果
// 输入格式的转化及偏差计算
set = target;
input = feedback;
iError = set - input; // 偏差
e = iError;
ec = iError - pri->lasterror;
// 当温度差的绝对值小于Emax时对pid的参数进行调整
if (fabs(iError) <= Emax)
{
// 计算iError在es与ecs中各项的隶属度
es[NB] = FTraL(e * 5, -3, -1); // e
es[NM] = FTri(e * 5, -3, -2, 0);
es[NS] = FTri(e * 5, -3, -1, 1);
es[ZO] = FTri(e * 5, -2, 0, 2);
es[PS] = FTri(e * 5, -1, 1, 3);
es[PM] = FTri(e * 5, 0, 2, 3);
es[PB] = FTraR(e * 5, 1, 3);
ecs[NB] = FTraL(ec * 30, -3, -1); // ec
ecs[NM] = FTri(ec * 30, -3, -2, 0);
ecs[NS] = FTri(ec * 30, -3, -1, 1);
ecs[ZO] = FTri(ec * 30, -2, 0, 2);
ecs[PS] = FTri(ec * 30, -1, 1, 3);
ecs[PM] = FTri(ec * 30, 0, 2, 3);
ecs[PB] = FTraR(ec * 30, 1, 3);
// 计算隶属度表确定e和ec相关联后表格各项隶属度的值
for (i = 0; i < 7; i++)
{
for (j = 0; j < 7; j++)
{
form[i][j] = fand(es[i], ecs[j]);
}
}
// 取出具有最大隶属度的那一项
for (i = 0; i < 7; i++)
{
for (j = 0; j < 7; j++)
{
if (form[MaxX][MaxY] < form[i][j])
{
MaxX = i;
MaxY = j;
}
}
}
// 进行模糊推理,并去模糊
lsd = form[MaxX][MaxY];
temp_p = kp[MaxX][MaxY];
temp_d = kd[MaxX][MaxY];
temp_i = ki[MaxX][MaxY];
if (temp_p == NB)
detkp = uFTraL(lsd, -0.3, -0.1);
else if (temp_p == NM)
detkp = uFTri(lsd, -0.3, -0.2, 0);
else if (temp_p == NS)
detkp = uFTri(lsd, -0.3, -0.1, 0.1);
else if (temp_p == ZO)
detkp = uFTri(lsd, -0.2, 0, 0.2);
else if (temp_p == PS)
detkp = uFTri(lsd, -0.1, 0.1, 0.3);
else if (temp_p == PM)
detkp = uFTri(lsd, 0, 0.2, 0.3);
else if (temp_p == PB)
detkp = uFTraR(lsd, 0.1, 0.3);
if (temp_d == NB)
detkd = uFTraL(lsd, -3, -1);
else if (temp_d == NM)
detkd = uFTri(lsd, -3, -2, 0);
else if (temp_d == NS)
detkd = uFTri(lsd, -3, 1, 1);
else if (temp_d == ZO)
detkd = uFTri(lsd, -2, 0, 2);
else if (temp_d == PS)
detkd = uFTri(lsd, -1, 1, 3);
else if (temp_d == PM)
detkd = uFTri(lsd, 0, 2, 3);
else if (temp_d == PB)
detkd = uFTraR(lsd, 1, 3);
if (temp_i == NB)
detki = uFTraL(lsd, -0.06, -0.02);
else if (temp_i == NM)
detki = uFTri(lsd, -0.06, -0.04, 0);
else if (temp_i == NS)
detki = uFTri(lsd, -0.06, -0.02, 0.02);
else if (temp_i == ZO)
detki = uFTri(lsd, -0.04, 0, 0.04);
else if (temp_i == PS)
detki = uFTri(lsd, -0.02, 0.02, 0.06);
else if (temp_i == PM)
detki = uFTri(lsd, 0, 0.04, 0.06);
else if (temp_i == PB)
detki = uFTraR(lsd, 0.02, 0.06);
// pid三项系数的修改
pri->pKp += detkp;
pri->pKi += detki;
if (pri->kd_e)
{
pri->pKd += detkd;
}
else
{
pri->pKd = 0; // 取消微分作用
}
// 对Kp,Ki进行限幅
if (pri->pKp < 0)
{
pri->pKp = 0;
}
if (pri->pKi < 0)
{
pri->pKi = 0;
}
// 计算新的K1,nKi,nKd
pri->nKp = pri->pKp + pri->pKi + pri->pKd;
pri->nKi = -(pri->pKp + 2 * pri->pKd);
pri->nKd = pri->pKd;
}
if (iError > Emax)
{
pri->out = pri->max;
pwm_var = 0;
pri->flag = 1; // 设定标志位,如果误差超过了门限值,则认为当控制量第一次到达给定值时,应该采取下面的 抑制超调 的措施
}
else if (iError < -Emax)
{
pri->out = pri->min;
pwm_var = 0;
}
else if (fabsf(iError) <= Emin)
{
pwm_var = 0;
}
else
{
if (iError < Emid && pri->flag == 1) // 第一次超过(设定值-Emid(-0.08)摄氏度),是输出为零,防止超调,也可以输出其他值,不至于太小而引起震荡
{
pri->out = 0;
pri->flag = 0;
}
else if (-iError > Emid) // 超过(设定+Emid(+0.08)摄氏度)
{
pwm_var = -1;
}
else
{
// 增量计算
pwm_var = (pri->nKp * iError // e[k]
+ pri->nKi * pri->lasterror // e[k-1]
+ pri->nKd * pri->preverror); // e[k-2]
}
if (pwm_var >= Umax)
pwm_var = Umax; // 调整值限幅,防止积分饱和
if (pwm_var <= Umin)
pwm_var = Umin; // 调整值限幅,防止积分饱和
}
pri->preverror = pri->lasterror;
pri->lasterror = iError;
pri->out += pwm_var; // 调整PWM输出
if (pri->out > pri->max)
pri->out = pri->max; // 输出值限幅
if (pri->out < pri->min)
pri->out = pri->min; // 输出值限幅
return pri->out;
}
/*整定开始前的预处理,判断状态及初始化变量*/
static void tune_pretreatment(struct PID_X *self)
{
CLASSIC_AUTOTUNE *tune = &self->tune;
CLASSICPID *vPID = &self->pri;
tune->tuneTimer = 0;
tune->startTime = 0;
tune->endTime = 0;
tune->outputStep = 100;
if (*vPID->pSV >= *vPID->pPV)
{
tune->initialStatus = 1;
tune->outputStatus = 0;
}
else
{
tune->initialStatus = 0;
tune->outputStatus = 1;
}
tune->tuneEnable = 1;
tune->preEnable = 0;
tune->zeroAcrossCounter = 0;
tune->riseLagCounter = 0;
tune->fallLagCounter = 0;
}
/*计算PID参数值*/
static void calculation_parameters(struct PID_X *self)
{
CLASSIC_AUTOTUNE *tune = &self->tune;
CLASSICPID *vPID = &self->pri;
float32 kc = 0.0f;
float32 tc = 0.0f;
float32 zn[3][3] = {{0.5f, 100000.0f, 0.0f}, {0.45f, 0.8f, 0.0f}, {0.6f, 0.5f, 0.125f}};
tc = (tune->endTime - tune->startTime) * tune->tunePeriod / 1000.0;
kc = (8.0f * tune->outputStep) / (PI * (tune->maxPV - tune->minPV));
vPID->pKp = zn[tune->controllerType][0] * kc; // 比例系数
vPID->pKi = vPID->pKp * tune->tunePeriod / (zn[tune->controllerType][1] * tc); // 积分系数
vPID->pKd = vPID->pKp * zn[tune->controllerType][2] * tc / tune->tunePeriod; // 微分系数
}
/**
* @brief
* @param {PID_X} *self
* @return {*}
* @note tuneEnablepreEnable和controllerType需要提前赋值tuneEnable变量值为0时是使用PID控制器tuneEnable变量值为1时是开启整定过程tuneEnable变量值为2时是指示整定失败preEnable变量在整定前赋值为1controllerType则根据所整定的控制器的类型来定
*/
static uint8_t _auto_tune(struct PID_X *self)
{
CLASSIC_AUTOTUNE *tune = &self->tune;
CLASSICPID *vPID = &self->pri;
/*整定开始前的预处理,只执行一次*/
if (tune->preEnable == 1)
{
tune_pretreatment(self);
}
uint32_t tuneDuration = 0;
tune->tuneTimer++;
tuneDuration = (tune->tuneTimer * tune->tunePeriod) / 1000;
if (tuneDuration > (10 * 60)) // 整定过程持续超过10分钟未能形成有效振荡整定失败
{
tune->tuneEnable = 2;
tune->preEnable = 1;
return tune->tuneEnable;
}
if (*vPID->pSV >= *vPID->pPV) // 设定值大于测量值,则开执行单元
{
tune->riseLagCounter++;
tune->fallLagCounter = 0;
if (tune->riseLagCounter > LAG_PHASE)
{
*vPID->pMV = vPID->max;
if (tune->outputStatus == 0)
{
tune->outputStatus = 1;
tune->zeroAcrossCounter++;
if (tune->zeroAcrossCounter == 3)
{
tune->startTime = tune->tuneTimer;
}
}
}
}
else
{
tune->riseLagCounter = 0;
tune->fallLagCounter++;
if (tune->fallLagCounter > LAG_PHASE)
{
*vPID->pMV = vPID->min;
if (tune->outputStatus == 1)
{
tune->outputStatus = 0;
tune->zeroAcrossCounter++;
if (tune->zeroAcrossCounter == 3)
{
tune->startTime = tune->tuneTimer;
}
}
}
}
if (tune->zeroAcrossCounter == 3) // 已经两次过零,可以记录波形数据
{
if (tune->initialStatus == 1) // 初始设定值大于测量值则区域3出现最小值
{
if (*vPID->pPV < tune->minPV)
{
tune->minPV = *vPID->pPV;
}
}
else if (tune->initialStatus == 0) // 初始设定值小于测量值则区域3出现最大值
{
if (*vPID->pPV > tune->maxPV)
{
tune->maxPV = *vPID->pPV;
}
}
}
else if (tune->zeroAcrossCounter == 4) // 已经三次过零,记录另半波的数据
{
if (tune->initialStatus == 1) // 初始设定值大于测量值则区域4出现最大值
{
if (*vPID->pPV > tune->maxPV)
{
tune->maxPV = *vPID->pPV;
}
}
else if (tune->initialStatus == 0) // 初始设定值小于测量值则区域4出现最小值
{
if (*vPID->pPV < tune->minPV)
{
tune->minPV = *vPID->pPV;
}
}
}
else if (tune->zeroAcrossCounter == 5) // 已经四次过零,振荡已形成可以整定参数
{
calculation_parameters(self);
tune->tuneEnable = 0;
tune->preEnable = 1;
}
return tune->tuneEnable;
}
void pid_x_constructor(struct PID_X *self)
{
self->PID = _PID;
self->AUTO_TUNE = _auto_tune;
self->pri.flag = 0;
self->pri.out = 0;
self->tune.preEnable = 1;
}

View File

@ -0,0 +1,71 @@
#ifndef __PID_X_H__
#define __PID_X_H__
#include "lib.h"
/*定义PID对象类型*/
typedef struct CLASSIC
{
float32 *pPV; // 测量值指针
float32 *pSV; // 设定值指针
float32 *pMV; // 输出值指针
BOOL *pMA; // 手自动操作指针
float32 out; // 输出值
float32 setpoint; // 设定值
float32 lasterror; // 前一拍偏差
float32 preverror; // 前两拍偏差
float32 max; // 输出值上限
float32 min; // 输出值下限
uint16_t flag; // 状态标志位
float32 pKp; // 比例系数
float32 pKi; // 积分系数
float32 pKd; // 微分系数
float32 nKp; // 比例系数
float32 nKi; // 积分系数
float32 nKd; // 微分系数
BOOL direct; // 正反作用
BOOL sm; // 设定值平滑
BOOL cas; // 串级设定
BOOL pac; // 输出防陡变
BOOL kd_e; // 微分使能
} CLASSICPID;
// 定义整定参数
typedef struct
{
uint8_t tuneEnable : 2; // 整定与PID控制开关0PID控制1参数整定2整定失败
uint8_t preEnable : 2; // 预处理使能,在开始整定前置位
uint8_t initialStatus : 1; // 记录开始整定前偏差的初始状态
uint8_t outputStatus : 1; // 记录输出的初始状态0允许上升过零计数1允许下降过零计数
uint8_t controllerType : 2; // 控制器类型0P控制器1PI控制器2PID控制器
uint8_t zeroAcrossCounter; // 过零点计数器每次输出改变加1比实际过零次数多1
uint8_t riseLagCounter; // 上升迟滞时间计数器
uint8_t fallLagCounter; // 下降迟滞时间计数器
uint16_t tunePeriod; // 整定采样周期
uint32_t tuneTimer; // 整定计时器
uint32_t startTime; // 记录波形周期起始时间
uint32_t endTime; // 记录波形周期结束时间
float32 outputStep; // 输出阶跃d
float32 maxPV; // 振荡波形中测量值的最大值
float32 minPV; // 振荡波形中测量值的最小值
} CLASSIC_AUTOTUNE;
typedef struct PID_X
{
/* 控制接口 */
float32 (*PID)(struct PID_X *self, float32 target, float32 feedback);
uint8_t (*AUTO_TUNE)(struct PID_X *self);
/* private */
CLASSICPID pri;
CLASSIC_AUTOTUNE tune;
} pid_x_t;
extern void pid_x_constructor(struct PID_X *self);
#endif // __PID_X_H__

View File

@ -0,0 +1,467 @@
#include "pid_zh.h"
#include "sys.h"
#include <math.h>
// 定义输出量比例因子
#ifdef GPS3000
#define KUP 0.0f // #define KUP 3.0f
#define KUI 0.00f
#define KUD 0.0f // #define KUP 3.0f
#else
#define KUP 3.0f
#define KUI 0.0f
#define KUD 0.0f
#endif
// 模糊集合
#define NL -3
#define NM -2
#define NS -1
#define ZE 0
#define PS 1
#define PM 2
#define PL 3
// 定义偏差E的范围因为设置了非线性区间误差在10时才开始进行PID调节这里E的范围为10
#define MAXE (10)
#define MINE (-MAXE)
// 定义EC的范围因为变化非常缓慢每次的EC都非常小这里可以根据实际需求来调整
#define MAXEC (10)
#define MINEC (-MAXEC)
// 定义e,ec的量化因子
#define KE 3 / MAXE
#define KEC 3 / MAXEC
static const float32 fuzzyRuleKp[7][7] = {
PL, PL, PM, PL, PS, PM, PL,
PL, PM, PM, PM, PS, PM, PL,
PM, PS, PS, PS, PS, PS, PM,
PM, PS, ZE, ZE, ZE, PS, PM,
PS, PS, PS, PS, PS, PM, PM,
PM, PM, PM, PM, PL, PL, PL,
PM, PL, PL, PL, PL, PL, PL};
static const float32 fuzzyRuleKi[7][7] = {
PL, PL, PL, PL, PM, PL, PL,
PL, PL, PM, PM, PM, PL, PL,
PM, PM, PS, PS, PS, PM, PM,
PM, PS, ZE, ZE, ZE, PS, PM,
PM, PS, PS, PS, PS, PM, PM,
PM, PM, PS, PM, PM, PL, PL,
PM, PL, PM, PL, PL, PL, PL};
/*
static const float32 fuzzyRuleKi[7][7] = {
NL, NL, NL, NL, NM, NL, NL,
NL, NL, NM, NM, NM, NL, NL,
NM, NM, NS, NS, NS, NM, NM,
NM, NS, ZE, ZE, ZE, NS, NM,
NM, NS, NS, NS, NS, NM, NM,
NM, NM, NS, NM, NM, NL, NL,
NM, NL, NM, NL, NL, NL, NL};
*/
static const float32 fuzzyRuleKd[7][7] = {
PS, PS, ZE, ZE, ZE, PL, PL,
PS, PS, PS, PS, ZE, PS, PM,
PL, PL, PM, PS, ZE, PS, PM,
PL, PM, PM, PS, ZE, PS, PM,
PL, PM, PS, PS, ZE, PS, PS,
PM, PS, PS, PS, ZE, PS, PS,
PS, ZE, ZE, ZE, ZE, PL, PL};
/*
static const float32 fuzzyRuleKp[7][7] = {
PL, PL, PM, PM, PS, ZE, ZE,
PL, PL, PM, PS, PS, ZE, NS,
PM, PM, PM, PS, ZE, NS, NS,
PM, PM, PS, ZE, NS, NM, NM,
PS, PS, ZE, NS, NS, NM, NM,
PS, ZE, NS, NM, NM, NM, NL,
ZE, ZE, NM, NM, NM, NL, NL};
static const float32 fuzzyRuleKi[7][7] = {
NL, NL, NM, NM, NS, ZE, ZE,
NL, NL, NM, NS, NS, ZE, ZE,
NL, NM, NS, NS, ZE, PS, PS,
NM, NM, NS, ZE, PS, PM, PM,
NM, NS, ZE, PS, PS, NM, PL,
ZE, ZE, PS, PS, PM, PL, PL,
ZE, ZE, PS, PM, PM, PL, PL};
static const float32 fuzzyRuleKd[7][7] = {
PS, NS, NL, NL, NL, NM, PS,
PS, NS, NL, NM, NM, NS, ZE,
ZE, NS, NM, NM, NS, NS, ZE,
ZE, NS, NS, NS, NS, NS, ZE,
ZE, ZE, ZE, ZE, ZE, ZE, ZE,
PL, NS, PS, PS, PS, PS, PL,
PL, PM, PM, PM, PS, PS, PL};
*/
static void fuzzy(float32 e, float32 ec, FUZZY_PID_ZH_t *fuzzy_pid)
{
float32 etemp, ectemp;
float32 eLefttemp, ecLefttemp; // ec,e左隶属度
float32 eRighttemp, ecRighttemp;
int eLeftIndex, ecLeftIndex; // 模糊位置标号
int eRightIndex, ecRightIndex;
e = RANGE(e, MINE, MAXE);
ec = RANGE(ec, MINEC, MAXEC);
e = e * KE;
ec = ec * KEC;
etemp = e > 3.0f ? 0.0f : (e < -3.0f ? 0.0f : (e >= 0.0f ? (e >= 2.0f ? 2.5f : (e >= 1.0f ? 1.5f : 0.5f)) : (e >= -1.0f ? -0.5f : (e >= -2.0f ? -1.5f : (e >= -3.0f ? -2.5f : 0.0f)))));
eLeftIndex = (int)((etemp - 0.5f) + 3); //[-3,2] -> [0,5]
eRightIndex = (int)((etemp + 0.5f) + 3);
eLefttemp = etemp == 0.0f ? 0.0f : ((etemp + 0.5f) - e);
eRighttemp = etemp == 0.0f ? 0.0f : (e - (etemp - 0.5f));
ectemp = ec > 3.0f ? 0.0f : (ec < -3.0f ? 0.0f : (ec >= 0.0f ? (ec >= 2.0f ? 2.5f : (ec >= 1.0f ? 1.5f : 0.5f)) : (ec >= -1.0f ? -0.5f : (ec >= -2.0f ? -1.5f : (ec >= -3.0f ? -2.5f : 0.0f)))));
ecLeftIndex = (int)((ectemp - 0.5f) + 3); //[-3,2] -> [0,5]
ecRightIndex = (int)((ectemp + 0.5f) + 3);
ecLefttemp = ectemp == 0.0f ? 0.0f : ((ectemp + 0.5f) - ec);
ecRighttemp = ectemp == 0.0f ? 0.0f : (ec - (ectemp - 0.5f));
/*************************************反模糊*************************************/
fuzzy_pid->kp = (eLefttemp * ecLefttemp * fuzzyRuleKp[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKp[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKp[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKp[eRightIndex][ecRightIndex]);
fuzzy_pid->ki = (eLefttemp * ecLefttemp * fuzzyRuleKi[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKi[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKi[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKi[eRightIndex][ecRightIndex]);
fuzzy_pid->kd = (eLefttemp * ecLefttemp * fuzzyRuleKd[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKd[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKd[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKd[eRightIndex][ecRightIndex]);
// 对解算出的KP,KI,KD进行量化映射
fuzzy_pid->kp = fuzzy_pid->kp * fuzzy_pid->kup;
fuzzy_pid->ki = fuzzy_pid->ki * fuzzy_pid->kui;
fuzzy_pid->kd = fuzzy_pid->kd * fuzzy_pid->kud;
}
static void smoothSetpoint(struct PID_FUZZY_ZH *self, float32 target_sv)
{
#if FUZZY_SUB_TYPE == PID_SUB_TYPE_POSITION
pid_zh_position_t *pri = &self->pri;
#else
pid_common_increment_t *pri = &self->pri;
#endif
float32 stepIn = (pri->sv_range) * 0.1f;
float32 kFactor = 0.0f;
if (fabs(pri->ref - target_sv) <= stepIn)
{
pri->ref = target_sv;
}
else
{
if (pri->ref - target_sv > 0)
{
kFactor = -1.0f;
}
else if (pri->ref - target_sv < 0)
{
kFactor = 1.0f;
}
else
{
kFactor = 0.0f;
}
pri->ref = pri->ref + kFactor * stepIn;
}
}
/*封装模糊接口*/
static void compensate(float32 e, float32 ec, FUZZY_PID_ZH_t *fuzzy_d)
{
fuzzy(e, ec, fuzzy_d);
}
/**
* @brief PID积分及微分控制数据
* @param {PID_FUZZY_ZH} *self
* @return {*}
*/
static void _restctrl(struct PID_FUZZY_ZH *self)
{
self->pri.pre_error = 0;
self->pri.sum_iterm = 0;
#if INCOMPLETE_DIFFEREN == 1
self->pri.lastdev = 0;
#endif
}
/**
* @brief
* @param {PID_FUZZY_ZH} *self
* @param {float32} out_min
* @param {float32} out_max
* @return {*}
* @note
*/
static void _set_range(struct PID_FUZZY_ZH *self, float32 out_min, float32 out_max)
{
self->pri.out_max = out_max;
self->pri.out_min = out_min;
}
/**
* @brief 使
* @param {PID_FUZZY_ZH} *self
* @param {BOOL} enable
* @return {*}
* @note
*/
// static void _set_ki_enable(struct PID_FUZZY_ZH *self, BOOL enable)
// {
// self->pri.ki_enable = enable;
// }
/**
* @brief 使
* @param {PID_FUZZY_ZH} *self
* @param {BOOL} enable
* @return {*}
* @note
*/
static void _set_kd_enable(struct PID_FUZZY_ZH *self, BOOL enable)
{
self->pri.kd_enable = enable;
}
/*
* Function:使
* parameter:*pid需要配PID参数结构指针sv_range控制范围sv的范围
* return:
*/
static void _set_smooth_enable(struct PID_FUZZY_ZH *self, BOOL enable, float32 sv_range)
{
#if FUZZY_SUB_TYPE == PID_SUB_TYPE_POSITION
pid_zh_position_t *pri = &self->pri;
#else
pid_common_increment_t *pri = &self->pri;
#endif
pri->sm = enable;
pri->sv_range = sv_range;
}
// 设置控制参数
static void _set_ctrl_prm(struct PID_FUZZY_ZH *self, float32 kp, float32 ki, float32 kd, float32 err_dead,
float32 out_min, float32 out_max)
{
self->open = TRUE;
self->fuzzy.kup = KUP;
self->fuzzy.kui = KUI;
self->fuzzy.kud = KUD;
#if FUZZY_SUB_TYPE == PID_SUB_TYPE_POSITION
pid_zh_position_t *pri = &self->pri;
osel_memset((uint8_t *)pri, 0, sizeof(pid_zh_position_t));
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->err_dead = err_dead;
pri->out_max = out_max;
pri->out_min = out_min;
pri->detach = FALSE;
pri->sm = FALSE;
#else
pid_common_increment_t *pri = &self->pri;
osel_memset((uint8_t *)pri, 0, sizeof(pid_common_increment_t));
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->err_dead = err_dead;
pri->out_max = out_max;
pri->out_min = out_min;
#endif
if (kd > 0)
{
pri->kd_enable = TRUE;
}
else
{
pri->kd_enable = FALSE;
}
}
static void _update_ctrl_prm(struct PID_FUZZY_ZH *self, float32 kp, float32 ki, float32 kd, float32 err_dead,
float32 out_min, float32 out_max)
{
#if FUZZY_SUB_TYPE == PID_SUB_TYPE_POSITION
pid_zh_position_t *pri = &self->pri;
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->err_dead = err_dead;
pri->out_max = out_max;
pri->out_min = out_min;
pri->detach = FALSE;
pri->sm = FALSE;
#else
pid_common_increment_t *pri = &self->pri;
pri->kp = kp;
pri->ki = ki;
pri->kd = kd;
pri->err_dead = err_dead;
pri->out_max = out_max;
pri->out_min = out_min;
#endif
if (kd > 0)
{
pri->kd_enable = TRUE;
}
else
{
pri->kd_enable = FALSE;
}
}
/**
* @brief 0+PID,PID
* @param {PID_FUZZY_ZH} *self
* @param {float32} max_err
* @param {BOOL} mode
* @return {*}
*/
static void _set_cfg(struct PID_FUZZY_ZH *self, float32 max_err, BOOL mode)
{
self->pri.err_limit = max_err;
self->pri.detach = mode == FALSE ? FALSE : TRUE;
}
#if FUZZY_SUB_TYPE == PID_SUB_TYPE_POSITION
static float32 _PID(struct PID_FUZZY_ZH *self, float32 target, float32 feedback)
{
float32 error = 0;
float32 insert = 0;
float32 ec = 0;
float32 kd = 0;
#if INCOMPLETE_DIFFEREN == 1
float32 thisdev = 0;
#else
// float32 dinput = 0.0f;
#endif
float32 temp_iterm = 0.0f;
pid_zh_position_t *pri = &self->pri;
/*获取期望值与实际值,进行偏差计算*/
if (pri->sm == 1)
{
smoothSetpoint(self, target);
}
else
{
pri->ref = target;
}
pri->feed_back = feedback;
error = pri->ref - pri->feed_back;
if (fabs(error) <= pri->err_dead)
error = 0;
/* fuzzy control caculate */
ec = error - pri->pre_error;
if (self->open == TRUE)
{
compensate(error, ec, &self->fuzzy);
}
/*根据PID配置的模式,获取积分数据,进行积分累加*/
if (pri->out >= pri->out_max)
{
if (fabs(error) > pri->err_limit && pri->detach)
{
insert = 0;
}
else
{
insert = 1;
if (error < 0)
{
temp_iterm = (pri->ki + self->fuzzy.ki) * error;
}
}
}
else if (pri->out <= pri->out_min)
{
if (fabs(error) > pri->err_limit && pri->detach)
{
insert = 0;
}
else
{
insert = 1;
if (error > 0)
{
temp_iterm = (pri->ki + self->fuzzy.ki) * error;
}
}
}
else
{
if (fabs(error) > pri->err_limit && pri->detach)
{
insert = 0;
}
else
{
insert = 1;
temp_iterm = (pri->ki + self->fuzzy.ki) * error;
}
}
pri->sum_iterm += temp_iterm;
/* limt integral */
pri->sum_iterm = RANGE(pri->sum_iterm, pri->out_min, pri->out_max);
/*
if (pri->sum_ref)
pri->sum_iterm = RANGE(pri->sum_iterm, pri->sum_ref - 1.0f, pri->sum_ref + 1.0f);
else
pri->sum_iterm = RANGE(pri->sum_iterm, pri->out_min, pri->out_max);
*/
#if INCOMPLETE_DIFFEREN == 1
/*不完全微分*/
thisdev = (pri->kd + self->fuzzy.kd) * (1.0 - pri->alpha) * (error - pri->pre_error) + pri->alpha * pri->lastdev;
/*caculate pid out*/
pri->out = (pri->kp + self->fuzzy.kp) * error + pri->sum_iterm * insert + thisdev;
/*record last dev result*/
pri->lastdev = thisdev;
#else
if (pri->kd_enable == TRUE)
{
kd = pri->kd + self->fuzzy.kd;
}
else
{
kd = 0;
}
pri->out = (pri->kp + self->fuzzy.kp) * error + pri->sum_iterm * insert + (error - pri->pre_error) * (kd);
// pri->out += pri->sum_ref;
#endif
pri->pre_error = error;
/*record last feedback sensor result*/
pri->pre_feed_back = pri->feed_back;
/*limt pid output*/
pri->out = RANGE(pri->out, pri->out_min, pri->out_max);
return pri->out;
}
#else
#endif
void pid_zh_constructor(struct PID_FUZZY_ZH *self)
{
self->set_ctrl_prm = _set_ctrl_prm;
self->update_ctrl_prm = _update_ctrl_prm;
self->set_cfg = _set_cfg;
self->set_smooth_enable = _set_smooth_enable;
// self->set_ki_enable = _set_ki_enable;
self->set_kd_enable = _set_kd_enable;
self->set_range = _set_range;
self->restctrl = _restctrl;
self->PID = _PID;
}

View File

@ -0,0 +1,73 @@
#ifndef __PID_ZH_H__
#define __PID_ZH_H__
#include "lib.h"
#include "pid_auto_tune.h"
#define GPS2000
typedef struct
{
float32 ref;
float32 feed_back;
float32 pre_feed_back;
float32 pre_error;
float32 sum_ref;
float32 sum_iterm;
float32 kp;
float32 ki;
float32 kd;
float32 err_limit;
BOOL detach;
float32 err_dead;
#if INCOMPLETE_DIFFEREN == 1
float32 alpha;
float32 lastdev;
#endif
float32 out;
float32 out_max;
float32 out_min;
float32 sv_range;
BOOL sm;
BOOL ki_enable;
BOOL kd_enable;
} pid_zh_position_t; // 位置式PID
typedef struct
{
float32 kp;
float32 ki;
float32 kd;
float32 kup;
float32 kui;
float32 kud;
} FUZZY_PID_ZH_t;
// 模糊PID
typedef struct PID_FUZZY_ZH
{
/* 设置PID三个参数 */
void (*set_ctrl_prm)(struct PID_FUZZY_ZH *self, float32 kp, float32 ki, float32 kd, float32 err_dead,
float32 out_min, float32 out_max); // 设置PID参数
void (*update_ctrl_prm)(struct PID_FUZZY_ZH *self, float32 kp, float32 ki, float32 kd, float32 err_dead,
float32 out_min, float32 out_max); // 更新PID参数
void (*set_range)(struct PID_FUZZY_ZH *self, float32 out_min, float32 out_max); // 更新最大最小值
void (*set_cfg)(struct PID_FUZZY_ZH *self, float32 max_err, BOOL mode); // 配置PID模式,默认不使用积分分离
void (*set_smooth_enable)(struct PID_FUZZY_ZH *self, BOOL enable, float32 sv_range); // 设置平滑范围
// void (*set_ki_enable)(struct PID_FUZZY *self, BOOL enable);
// 微分开启使能
void (*set_kd_enable)(struct PID_FUZZY_ZH *self, BOOL enable);
void (*restctrl)(struct PID_FUZZY_ZH *self); // 复位PID积分及微分控制数据
/* 控制接口 */
float32 (*PID)(struct PID_FUZZY_ZH *self, float32 target, float32 feedback);
pid_zh_position_t pri;
BOOL open; // 是否使用模糊PID控制
FUZZY_PID_ZH_t fuzzy;
} pid_zh_t; // 模糊PID
extern void pid_zh_constructor(struct PID_FUZZY_ZH *self);
#endif

View File

@ -0,0 +1,619 @@
#include <math.h>
#include "pid_zh1.h"
// 定义输出量比例因子
#define KUP 1.0f
#define KUI 1.0f
#define KUD 1.0f
// 模糊集合
#define NL -3
#define NM -2
#define NS -1
#define ZE 0
#define PS 1
#define PM 2
#define PL 3
// 定义偏差E的范围因为设置了非线性区间误差在10时才开始进行PID调节这里E的范围为10
#define MAXE (10)
#define MINE (-MAXE)
// 定义EC的范围因为变化非常缓慢每次的EC都非常小这里可以根据实际需求来调整
#define MAXEC (10)
#define MINEC (-MAXEC)
// 定义e,ec的量化因子
#define KE 3 / MAXE
#define KEC 3 / MAXEC
/*
static const float fuzzyRuleKp[7][7] = {
PL, PL, PM, PL, PS, PM, PL,
PL, PM, PM, PM, PS, PM, PL,
PM, PS, PS, PS, PS, PS, PM,
PM, PS, ZE, ZE, ZE, PS, PM,
PS, PS, PS, PS, PS, PM, PM,
PM, PM, PM, PM, PL, PL, PL,
PM, PL, PL, PL, PL, PL, PL};
static const float fuzzyRuleKi[7][7] = {
PL, PL, PL, PL, PM, PL, PL,
PL, PL, PM, PM, PM, PL, PL,
PM, PM, PS, PS, PS, PM, PM,
PM, PS, ZE, ZE, ZE, PS, PM,
PM, PS, PS, PS, PS, PM, PM,
PM, PM, PS, PM, PM, PL, PL,
PM, PL, PM, PL, PL, PL, PL};
static const float fuzzyRuleKd[7][7] = {
PS, PS, ZE, ZE, ZE, PL, PL,
PS, PS, PS, PS, ZE, PS, PM,
PL, PL, PM, PS, ZE, PS, PM,
PL, PM, PM, PS, ZE, PS, PM,
PL, PM, PS, PS, ZE, PS, PS,
PM, PS, PS, PS, ZE, PS, PS,
PS, ZE, ZE, ZE, ZE, PL, PL};
*/
static const float fuzzyRuleKp[7][7] = {
PL, PL, PM, PL, PS, PM, PL,
PL, PM, PM, PM, PS, PM, PL,
PM, PS, PS, PS, PS, PS, PM,
PM, PS, ZE, ZE, ZE, PS, PM,
PS, PS, PS, PS, PS, PM, PM,
PM, PM, PM, PM, PL, PL, PL,
PM, PL, PL, PL, PL, PL, PL};
static const float fuzzyRuleKi[7][7] = {
PL, PL, PL, PL, PM, PL, PL,
PL, PL, PM, PM, PM, PL, PL,
PM, PM, PS, PS, PS, PM, PM,
PM, PS, ZE, ZE, ZE, PS, PM,
PM, PS, PS, PS, PS, PM, PM,
PM, PM, PS, PM, PM, PL, PL,
PM, PL, PM, PL, PL, PL, PL};
static const float fuzzyRuleKd[7][7] = {
PS, PS, ZE, ZE, ZE, PL, PL,
PS, PS, PS, PS, ZE, PS, PM,
PL, PL, PM, PS, ZE, PS, PM,
PL, PM, PM, PS, ZE, PS, PM,
PL, PM, PS, PS, ZE, PS, PS,
PM, PS, PS, PS, ZE, PS, PS,
PS, ZE, ZE, ZE, ZE, PL, PL};
static void fuzzy(float e, float ec, fuzzy_pid_t *fuzzy_pid)
{
float etemp, ectemp;
float eLefttemp, ecLefttemp; // 左隶属度
float eRighttemp, ecRighttemp; // 右隶属度
int eLeftIndex, ecLeftIndex; // 模糊位置标号
int eRightIndex, ecRightIndex;
e = RANGE(e, MINE, MAXE);
ec = RANGE(ec, MINEC, MAXEC);
e = e * KE;
ec = ec * KEC;
etemp = e > 3.0f ? 0.0f : (e < -3.0f ? 0.0f : (e >= 0.0f ? (e >= 2.0f ? 2.5f : (e >= 1.0f ? 1.5f : 0.5f)) : (e >= -1.0f ? -0.5f : (e >= -2.0f ? -1.5f : (e >= -3.0f ? -2.5f : 0.0f)))));
eLeftIndex = (int)((etemp - 0.5f) + 3);
eRightIndex = (int)((etemp + 0.5f) + 3);
eLefttemp = etemp == 0.0f ? 0.0f : ((etemp + 0.5f) - e);
eRighttemp = etemp == 0.0f ? 0.0f : (e - (etemp - 0.5f));
ectemp = ec > 3.0f ? 0.0f : (ec < -3.0f ? 0.0f : (ec >= 0.0f ? (ec >= 2.0f ? 2.5f : (ec >= 1.0f ? 1.5f : 0.5f)) : (ec >= -1.0f ? -0.5f : (ec >= -2.0f ? -1.5f : (ec >= -3.0f ? -2.5f : 0.0f)))));
ecLeftIndex = (int)((ectemp - 0.5f) + 3);
ecRightIndex = (int)((ectemp + 0.5f) + 3);
ecLefttemp = ectemp == 0.0f ? 0.0f : ((ectemp + 0.5f) - ec);
ecRighttemp = ectemp == 0.0f ? 0.0f : (ec - (ectemp - 0.5f));
/*************************************反模糊*************************************/
fuzzy_pid->kp = (eLefttemp * ecLefttemp * fuzzyRuleKp[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKp[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKp[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKp[eRightIndex][ecRightIndex]);
fuzzy_pid->ki = (eLefttemp * ecLefttemp * fuzzyRuleKi[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKi[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKi[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKi[eRightIndex][ecRightIndex]);
fuzzy_pid->kd = (eLefttemp * ecLefttemp * fuzzyRuleKd[eLeftIndex][ecLeftIndex] + eLefttemp * ecRighttemp * fuzzyRuleKd[eLeftIndex][ecRightIndex] + eRighttemp * ecLefttemp * fuzzyRuleKd[eRightIndex][ecLeftIndex] + eRighttemp * ecRighttemp * fuzzyRuleKd[eRightIndex][ecRightIndex]);
// 对解算出的KP,KI,KD进行量化映射
fuzzy_pid->kp = fuzzy_pid->kp * fuzzy_pid->kup;
fuzzy_pid->ki = fuzzy_pid->ki * fuzzy_pid->kui;
fuzzy_pid->kd = fuzzy_pid->kd * fuzzy_pid->kud;
}
static void smooth_init(smart_pid_t *pid, BOOL sm_open, float maxTarget)
{
if (!pid)
return;
pid->sm_open = sm_open;
pid->maxTarget = maxTarget;
}
static void smooth_target(smart_pid_t *pid, float *target)
{
if ((!pid) || (!target))
return;
if (!pid->maxTarget)
return;
float sm_step = (pid->maxTarget) * 0.1f;
float k = 0.0f;
if (fabs(pid->target - *target) <= sm_step)
{
pid->target = *target;
}
else
{
if (pid->target - *target > 0)
{
k = -1.0f;
}
else if (pid->target - *target < 0)
{
k = 1.0f;
}
else
{
k = 0.0f;
}
pid->target += k * sm_step;
}
}
static void smart_pid_init(smart_pid_t *pid, float *duty, float *kp, float *ki, float *kd, float *errorDead, float *iDetachCondation, float *maxOut)
{
if ((!pid) || (!duty) || (!kp) || (!ki) || (!kd) || (!iDetachCondation) || (!maxOut))
return;
pid->duty = *duty;
pid->kp = *kp;
pid->ki = *ki;
pid->kd = *kd;
pid->errorDead = *errorDead;
pid->iDetachCondation = *iDetachCondation;
pid->maxOutput = *maxOut;
}
void cascade_pid_init(cascade_pid_t *pid, smart_pid_t *pid_outer, smart_pid_t *pid_inner)
{
smooth_init(&pid->outer, pid_outer->sm_open, pid_outer->maxTarget);
smooth_init(&pid->inner, pid_inner->sm_open, pid_inner->maxTarget);
smart_pid_init(&pid->outer, &pid_outer->duty, &pid_outer->kp, &pid_outer->ki, &pid_outer->kd, &pid_outer->errorDead, &pid_outer->iDetachCondation, &pid_outer->maxOutput);
smart_pid_init(&pid->inner, &pid_inner->duty, &pid_inner->kp, &pid_inner->ki, &pid_inner->kd, &pid_inner->errorDead, &pid_inner->iDetachCondation, &pid_inner->maxOutput);
}
void smart_pid_calc(smart_pid_t *pid, float *target, float *feedback)
{
// 将旧error存起来
pid->lastError = pid->error;
// 平滑处理目标值
if (pid->sm_open == TRUE)
smooth_target(pid, target);
else
pid->target = *target;
// 计算新error
pid->error = pid->target - *feedback;
if (fabs(pid->error) <= pid->errorDead)
pid->error = 0.0f;
// 计算误差变化
pid->dError = pid->error - pid->lastError;
// 选用模糊规则
if (pid->fuzzy_open == TRUE)
{
fuzzy(pid->error, pid->dError, &pid->fuzzy_pid);
}
// 计算微分
float dout = pid->dError * (pid->kd + pid->fuzzy_pid.kd);
// 计算比例
float pout = pid->error * (pid->kp + pid->fuzzy_pid.kp);
// 积分分离
if (fabs(pid->error) <= pid->iDetachCondation)
{
pid->integral += pid->error * (pid->ki + pid->fuzzy_pid.ki);
pid->iDetach = FALSE;
}
else
{
pid->iDetach = TRUE;
pid->integral = 0;
}
// 积分限幅
if (pid->integral > pid->maxOutput)
pid->integral = pid->maxOutput;
else if (pid->integral < -pid->maxOutput)
pid->integral = -pid->maxOutput;
// 计算输出
pid->output = pout + dout + pid->integral * (!pid->iDetach);
// 输出限幅
if (pid->output > pid->maxOutput)
pid->output = pid->maxOutput;
else if (pid->output < -pid->maxOutput)
pid->output = -pid->maxOutput;
}
void cascade_pid_calc(struct CascadePID *pid, float *outerRef, float *outerFdb, float *innerFdb)
{
// 外环位置控制
smart_pid_calc(&pid->cascade_pid.outer, outerRef, outerFdb);
// 内环速度控制
smart_pid_calc(&pid->cascade_pid.inner, &pid->cascade_pid.outer.output, innerFdb);
// 内环输出就是串级PID的输出
// pid->cascade_pid.output = pid->cascade_pid.inner.output;
pid->cascade_pid.output = pid->cascade_pid.outer.output;
}
void pid_zh_constructor1(struct CascadePID *pid)
{
pid->smart_pid_init = smart_pid_init;
pid->smart_pid_calc = smart_pid_calc;
pid->cascade_pid_init = cascade_pid_init;
pid->cascade_pid_calc = cascade_pid_calc;
}
/*
L[1] -> 1/s
L[t] -> 1/s^2
L[1/2t^2] -> 1/s^3
G(s) = k/(TS+1)
G(s) = k/S^i(TS+1)
i = 0 0 i = 1 I I = 2 II
G(s)
G闭(s) = G(s) / 1 + G(s)
R(s) = 1/1+G(s)
limf(t) = lim s*G(s)
t-> s->0
o型系统r/s
e = lim f(t) = lim s*G(s) = G(s) = k/1+G(s) = k/ 1 + (Ts+1+k)..
t-> s->0 s->0 s->0 = s->0
*
*线
*
tr td tp
G(s) = 1/ s^2 *(2ξwn)s + wn^2
ξ:
wn = 1/T:
K T
RC电路
Gs = 1/Ts+1
EPM气压控制等主导环节
G(s) = wn^2/ s*( s + 2ξwn)
G(s) = wn^2/ (s^2 + (2ξwn)s + wn^2)
ξ
Wn
0 < ξ < 1
s^2 + (2ξwn)s + wn^2 = 0
I型系统来消除静差PID控制器
EPM本身的控制特性线性度差
EMP本身的控制线性度差EPM性能的不足
EPM IP开度大小决定EPM本身的不足
:
PID
    u(t) = k*(e(t) +e(t)dt + de(t)dt)
u(n) = k*(e(n) +  e(n)/Ti + Td*(e(n) - e(n-1)))
:PID + PD控制
    [-5%,5%] PID < 0.3%
    [-100%,5%] [5%,100%] PD控制
   
    <= 5%
              > 5%
   
              >= 100%   =  100%
              <= -100% = -100%
    : 60%
    : < 60%
    ->->,t0 -> -> -> ,t1
      <|
    Tu
    : Ku = - / ( - )
    Kp = 0.8 * Ku
          Ti = 0.6 * Tu
          Td = 0.125 * Tu
          Ki = Kp / Ti = Kp / (0.6 * Tu)
          Kd = Kp * Td = Kp * 0.125 * Td
    s1:AD值
    s2:AD值
    v1:
    v2:  
    v:
a
t:
v = (s2 - s1) / t
a = (v2 - v1) / t
   
    PID
    = -
    =
= Kp*  +  Ki *  + Kd *
   
   
      = -
      = -
      = Kp1*  +  Ki1 *  + Kd1 *
      = -
      = -
      = Kp2*  +  Ki2 *  + Kd2 *
???
automatic control theory
control system
linear and nonlinear system
线
modelling
analysis
线
L变换 Z变换
problems
time consuming
nyquist
0
root locus
G(s) = k/s(s+1)
线
p-n/n-m
lambda
lambda
tao/t
PI D
PID
makefile
1->->
#source object target
SRC := *.c
OBJ := *.o
TARGET := mqtt_test
#compile library include
CC := cc
LIB:= -lpthread
LDFLAG := -L. libmosquitto.so
CFLAG :=
CXXFLAG :=
#link
$(TARGET):$(OBJ)
$(CC) -o $(TARGET) $(BOJ) $(LIB) $(LDFLAG)
$(CC) -o $@ $^ $(LIB) $(LDFLAG)
$(OBJ):$(SRC)
$(CC) -c $(SRC)
#all
all:$(TARGET)
$(CC) -o $(TARGET) $(SRC) $(LIB) $(LDFLAG)
#clean
clean:
rm -rf *.o $(TARGET)
*/
// ————————————————————————————————————
/*
typedef struct
{
int argc;
char **argv;
int sock;
}st_app_param;
const char *g_version = "V1.0.0 24.08.16";
int child_mian_ini()
{
int i_re;
i_re = gw_support_init();
if(i_re < 0)
{
printf("解析支持文件错误.\n");
return -1;
}
i_re = gw_config_init();
if(i_re < 0)
{
printf("解析配置文件错误.\n");
return -1;
}
i_re = gw_data_init();
if(i_re < 0)
{
printf("数据初始化错误.\n");
return -1;
}
i_re = gw_modol_init();
if(i_re < 0)
{
printf("解析模型文件错误.\n");
return -1;
}
i_re = gw_stat_init();
if(i_re < 0)
{
printf("数据统计初始化错误.\n");
return -1;
}
i_re = gw_process_init();
if(i_re < 0)
{
printf("规约初始化错误.\n");
return -1;
}
i_re = gw_manage_init();
if(i_re < 0)
{
printf("界面通讯初始化错误.\n");
return -1;
}
pthread_create(tid,thread_task1,p_param);
while(1)
{
get_sys_time();
sleep(1);
}
}
int child_main(int argc,char **argv)
{
if((argc == 2)&&(strcasecmp(argv[1],"-version") == 0))
{
printf("version [%s]",g_version);
}
child_mian_ini();
}
static int run_child_process_thread((void *)param)
{
st_app_param *p_param;
p_param = param;
chlid_main(p_parm->argc,p_param->argv);
}
static int run_child_process(int argc,char **argv,int sock)
{
int i_re;
pthread_t *tid;
st_app_param p_param;
p_param.argc = argc;
p_param.argv = argv;
p_param.sock = sock;
pthread_creat(tid,run_child_process_thread,(void *)p_param);
i_re = recv(sock,..,0);//阻塞接收
send(sock,'q',0);
}
int main(int argc,char**argv)
{
int i_re,fd,pid;
char lock_file[16];
socketpair sockpaire[2];
sprintf(lock_file,"%s.lock",argv[0]);
fd = open(lock_file,_O_WRONLY|_EXC,0777);
if(fd < 0)
{
printf("应用:[%s]已运行.\n",argv[0]);
return 0;
}
sockpaire[0] = -1;
while(1)
{
i_re = socketpaire(sockpaire,AN_UNIX,..);
if(i_re < 0)
{
printf("[%d]创建sockpaire失败.\n",getpid());
return 0;
}
pid = fork();
if(pid < 0)
{
printf("[%d]创建进程失败.\n",getpid());
close(sockpaire[0]);
sockpaire[0] = -1
close(sockpaire[1]);
return 0;
}
if(pid == 0)//child process
{
close(sockpair[0]);
return run_child_process(argc,argv,sockpair[1]);
}
printf("[%d]创建子进程成功.\n",getpid());
close(sockpair[1]);
while(1)//father process
{
i_re = recv(sockpaire[0],....,0);//阻塞接收
if(i_re <= 0)
{
//连接中断,重连
sockpaire[0] = -1;
break;
}
else
{
//正常退出
goto EXIT:
}
}
EXIT:
//退出操作
if(sockpaire[0] == -1)
{
//有子进程,关闭子进程
}
close(fd);
unlink(file_lock);
}
}
*/

View File

@ -0,0 +1,63 @@
/*
* @Author: zxm5337@163.com
* @Date: 2024-06-25 10:26:36
* @LastEditors: DaMingSY zxm5337@163.com
* @LastEditTime: 2024-09-03 09:19:23
* @FilePath: \controller-v2\User\lib\control\custom\cascade_pid_zh.h
* @Description: ,`customMade`, koroFileHeader查看配置 : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
#ifndef __CASCADE_PID_ZH__
#define __CASCADE_PID_ZH__
#include "data_type_def.h"
typedef enum
{
TARGET_DIR_ADD,
TARGET_DIR_SUB,
} target_dir_e;
typedef struct
{
float kp;
float ki;
float kd;
float kup;
float kui;
float kud;
} fuzzy_pid_t;
typedef struct
{
BOOL iDetach, sm_open, fuzzy_open;
float feedBack;
float target, maxTarget;
float duty, kp, ki, kd;
float error, dError, lastError, errorDead;
float integral, iDetachCondation;
float output, maxOutput;
fuzzy_pid_t fuzzy_pid;
} smart_pid_t;
typedef struct
{
smart_pid_t inner;
smart_pid_t outer;
float output;
} cascade_pid_t;
typedef struct CascadePID
{
void (*smart_pid_init)(smart_pid_t *pid, float *duty, float *kp, float *ki, float *kd, float *errorDead, float *iDetachCondation, float *maxOut);
void (*cascade_pid_init)(cascade_pid_t *pid, smart_pid_t *pid_outer, smart_pid_t *pid_inner);
void (*smart_pid_calc)(smart_pid_t *pid, float *target, float *feedback);
void (*cascade_pid_calc)(struct CascadePID *pid, float *outerRef, float *outerFdb, float *innerFdb);
smart_pid_t smart_pid;
cascade_pid_t cascade_pid;
} pid_zh1_t; // PID_t;
extern void pid_zh_constructor1(struct CascadePID *pid);
#endif

View File

@ -0,0 +1,26 @@
# 架构
|文件|路径| <div style="width:300px">说明</div>|
|:--|:--|:--|
|pid|User\lib\control\src|PID算法模块|
|execute|User\application\src|执行器|
|app_flow|User|任务流程控制|
## APP_FLOW任务流程控制
> adjust_inspection 中在没有检测到调试信号时执行<b style="color:blue">execute_dac,EXECUTE_PLAN</b>定义了需要执行的算法任务计划
## PID算法模块
文件内容:
|文件| <div style="width:300px">说明</div>|
|:--|:--|
|pid.c|构造算法的入口|
|pid_common.c|普通算法|
|pid_neural.c|神经网络算法|
|pid_fuzzy.c|模糊算法|
<b style="color:blue">custom 目录下为各自算法实现</b>
## EXECUTE执行器
> execute_pid_init中定义了初始化参数
> execute_dac中定义了执行器

View File

@ -1,9 +1,17 @@
#ifndef __PID_H__ #ifndef __PID_H__
#define __PID_H__ #define __PID_H__
#include "lib.h" #include "lib.h"
#include "pid_auto_tune.h" #include "pid_auto_tune.h"
#define INCOMPLETE_DIFFEREN 0 // 不完全微分 #include "pid_c.h"
#include "pid_g.h"
#include "pid_x.h"
#include "pid_zh.h"
#include "pid_zh1.h"
#include "pid_hd.h"
#define INCOMPLETE_DIFFEREN 1 // 不完全微分
typedef enum typedef enum
{ {
@ -54,6 +62,7 @@ typedef struct
float32 err_limit; float32 err_limit;
BOOL detach; BOOL detach;
float32 err_dead; float32 err_dead;
// 不完全微分方式在微分环节采用了低通滤波有效地提高了微分项的特性。其中α的取值是一个0~1之间的数。两个极限值在0时其实就是没有滤波的普通微分环节而取1时则没有微分作用。所以α的取值对不完全微分的效果是至关重要的一般要根据被控对象的特性来确定
float32 alpha; float32 alpha;
float32 lastdev; float32 lastdev;
float32 out; float32 out;
@ -219,6 +228,14 @@ typedef struct
pid_common_t common; pid_common_t common;
pid_neural_t neural; pid_neural_t neural;
pid_fuzzy_t fuzzy; pid_fuzzy_t fuzzy;
// 自定义PID
pid_c_t cao;
pid_g_t gao;
pid_x_t xu;
pid_zh_t zhang;
pid_zh1_t zhang1;
pid_hd_t hd;
} pid_u; } pid_u;
pid_auto_tune_t auto_tune; pid_auto_tune_t auto_tune;
} pid_t; } pid_t;

View File

@ -20,6 +20,22 @@ void pid_constructor(pid_t *self)
case PID_TYPE_AUTO_TUNE: case PID_TYPE_AUTO_TUNE:
pid_auto_tune_constructor(&self->auto_tune); pid_auto_tune_constructor(&self->auto_tune);
break; break;
case PID_TYPE_CUSTOM_CAO:
pid_c_constructor(&self->pid_u.cao);
break;
case PID_TYPE_CUSTOM_GAO:
pid_g_constructor(&self->pid_u.gao);
break;
case PID_TYPE_CUSTOM_XU:
pid_x_constructor(&self->pid_u.xu);
break;
case PID_TYPE_CUSTOM_ZHANG:
// pid_zh_constructor(&self->pid_u.zhang);
pid_zh_constructor1(&self->pid_u.zhang1);
break;
case PID_TYPE_CUSTOM_HANGDIAN:
pid_hd_constructor(&self->pid_u.hd);
break;
default: default:
break; break;
} }

View File

@ -13,17 +13,17 @@
#define PL 3 #define PL 3
// 定义偏差E的范围因为设置了非线性区间误差在10时才开始进行PID调节这里E的范围为10 // 定义偏差E的范围因为设置了非线性区间误差在10时才开始进行PID调节这里E的范围为10
#define MAXE (100) #define MAXE (30)
#define MINE (-MAXE) #define MINE (-MAXE)
// 定义EC的范围因为变化非常缓慢每次的EC都非常小这里可以根据实际需求来调整 // 定义EC的范围因为变化非常缓慢每次的EC都非常小这里可以根据实际需求来调整
#define MAXEC (100) #define MAXEC (30)
#define MINEC (-MAXEC) #define MINEC (-MAXEC)
// 定义e,ec的量化因子 // 定义e,ec的量化因子
#define KE 3 / MAXE #define KE 3 / MAXE
#define KEC 3 / MAXEC #define KEC 3 / MAXEC
// 定义输出量比例因子 // 定义输出量比例因子
#define KUP 1.0f // 这里只使用了模糊PID的比例增益 #define KUP 3.0f // 这里只使用了模糊PID的比例增益
#define KUI 0.0f #define KUI 0.0f
#define KUD 0.0f #define KUD 0.0f
@ -442,6 +442,7 @@ static void _set_ctrl_prm(struct PID_FUZZY *self, float32 kp, float32 ki, float3
pri->detach = FALSE; pri->detach = FALSE;
pri->sm = FALSE; pri->sm = FALSE;
pri->ki_enable = TRUE; pri->ki_enable = TRUE;
pri->alpha = 0.25;
} }
else else
{ {
@ -456,6 +457,7 @@ static void _set_ctrl_prm(struct PID_FUZZY *self, float32 kp, float32 ki, float3
pri->out_max = out_max; pri->out_max = out_max;
pri->out_min = out_min; pri->out_min = out_min;
pri->ki_enable = TRUE; pri->ki_enable = TRUE;
pri->alpha = 0.25;
} }
} }

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief basic KV samples.
*
* basic Key-Value Database KV feature samples
* get and show currnet boot counts
*/
#include <flashdb.h>
#ifdef FDB_USING_KVDB
#define FDB_LOG_TAG "[sample][kvdb][basic]"
void kvdb_basic_sample(fdb_kvdb_t kvdb)
{
struct fdb_blob blob;
int boot_count = 0;
FDB_INFO("==================== kvdb_basic_sample ====================\n");
{ /* GET the KV value */
/* get the "boot_count" KV value */
fdb_kv_get_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
/* the blob.saved.len is more than 0 when get the value successful */
if (blob.saved.len > 0) {
FDB_INFO("get the 'boot_count' value is %d\n", boot_count);
} else {
FDB_INFO("get the 'boot_count' failed\n");
}
}
{ /* CHANGE the KV value */
/* increase the boot count */
boot_count ++;
/* change the "boot_count" KV's value */
fdb_kv_set_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
FDB_INFO("set the 'boot_count' value to %d\n", boot_count);
}
FDB_INFO("===========================================================\n");
}
#endif /* FDB_USING_KVDB */

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief blob KV samples.
*
* Key-Value Database blob type KV feature samples
*/
#include <flashdb.h>
#ifdef FDB_USING_KVDB
#define FDB_LOG_TAG "[sample][kvdb][blob]"
void kvdb_type_blob_sample(fdb_kvdb_t kvdb)
{
struct fdb_blob blob;
FDB_INFO("==================== kvdb_type_blob_sample ====================\n");
{ /* CREATE new Key-Value */
int temp_data = 36;
/* It will create new KV node when "temp" KV not in database.
* fdb_blob_make: It's a blob make function, and it will return the blob when make finish.
*/
fdb_kv_set_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
FDB_INFO("create the 'temp' blob KV, value is: %d\n", temp_data);
}
{ /* GET the KV value */
int temp_data = 0;
/* get the "temp" KV value */
fdb_kv_get_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
/* the blob.saved.len is more than 0 when get the value successful */
if (blob.saved.len > 0) {
FDB_INFO("get the 'temp' value is: %d\n", temp_data);
}
}
{ /* CHANGE the KV value */
int temp_data = 38;
/* change the "temp" KV's value to 38 */
fdb_kv_set_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
FDB_INFO("set 'temp' value to %d\n", temp_data);
}
{ /* DELETE the KV by name */
fdb_kv_del(kvdb, "temp");
FDB_INFO("delete the 'temp' finish\n");
}
FDB_INFO("===========================================================\n");
}
#endif /* FDB_USING_KVDB */

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief string KV samples.
*
* Key-Value Database string type KV feature samples source file.
*/
#include <flashdb.h>
#include <string.h>
#ifdef FDB_USING_KVDB
#define FDB_LOG_TAG "[sample][kvdb][string]"
void kvdb_type_string_sample(fdb_kvdb_t kvdb)
{
FDB_INFO("==================== kvdb_type_string_sample ====================\n");
{ /* CREATE new Key-Value */
char temp_data[10] = "36C";
/* It will create new KV node when "temp" KV not in database. */
fdb_kv_set(kvdb, "temp", temp_data);
FDB_INFO("create the 'temp' string KV, value is: %s\n", temp_data);
}
{ /* GET the KV value */
char *return_value, temp_data[10] = { 0 };
/* Get the "temp" KV value.
* NOTE: The return value saved in fdb_kv_get's buffer. Please copy away as soon as possible.
*/
return_value = fdb_kv_get(kvdb, "temp");
/* the return value is NULL when get the value failed */
if (return_value != NULL) {
strncpy(temp_data, return_value, sizeof(temp_data));
FDB_INFO("get the 'temp' value is: %s\n", temp_data);
}
}
{ /* CHANGE the KV value */
char temp_data[10] = "38C";
/* change the "temp" KV's value to "38.1" */
fdb_kv_set(kvdb, "temp", temp_data);
FDB_INFO("set 'temp' value to %s\n", temp_data);
}
{ /* DELETE the KV by name */
fdb_kv_del(kvdb, "temp");
FDB_INFO("delete the 'temp' finish\n");
}
FDB_INFO("===========================================================\n");
}
#endif /* FDB_USING_KVDB */

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief TSDB samples.
*
* Time series log (like TSDB) feature samples source file.
*
* TSL is time series log, the TSDB saved many TSLs.
*/
#include <flashdb.h>
#include <string.h>
#ifdef FDB_USING_TSDB
#define FDB_LOG_TAG "[sample][tsdb]"
#ifdef FDB_USING_TIMESTAMP_64BIT
#define __PRITS "ld"
#else
#define __PRITS "d"
#endif
struct env_status {
int temp;
int humi;
};
static bool query_cb(fdb_tsl_t tsl, void *arg);
static bool query_by_time_cb(fdb_tsl_t tsl, void *arg);
static bool set_status_cb(fdb_tsl_t tsl, void *arg);
void tsdb_sample(fdb_tsdb_t tsdb)
{
struct fdb_blob blob;
FDB_INFO("==================== tsdb_sample ====================\n");
{ /* APPEND new TSL (time series log) */
struct env_status status;
/* append new log to TSDB */
status.temp = 36;
status.humi = 85;
fdb_tsl_append(tsdb, fdb_blob_make(&blob, &status, sizeof(status)));
FDB_INFO("append the new status.temp (%d) and status.humi (%d)\n", status.temp, status.humi);
status.temp = 38;
status.humi = 90;
fdb_tsl_append(tsdb, fdb_blob_make(&blob, &status, sizeof(status)));
FDB_INFO("append the new status.temp (%d) and status.humi (%d)\n", status.temp, status.humi);
}
{ /* QUERY the TSDB */
/* query all TSL in TSDB by iterator */
fdb_tsl_iter(tsdb, query_cb, tsdb);
}
{ /* QUERY the TSDB by time */
/* prepare query time (from 1970-01-01 00:00:00 to 2020-05-05 00:00:00) */
struct tm tm_from = { .tm_year = 1970 - 1900, .tm_mon = 0, .tm_mday = 1, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
struct tm tm_to = { .tm_year = 2020 - 1900, .tm_mon = 4, .tm_mday = 5, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
time_t from_time = mktime(&tm_from), to_time = mktime(&tm_to);
size_t count;
/* query all TSL in TSDB by time */
fdb_tsl_iter_by_time(tsdb, from_time, to_time, query_by_time_cb, tsdb);
/* query all FDB_TSL_WRITE status TSL's count in TSDB by time */
count = fdb_tsl_query_count(tsdb, from_time, to_time, FDB_TSL_WRITE);
FDB_INFO("query count is: %zu\n", count);
}
{ /* SET the TSL status */
/* Change the TSL status by iterator or time iterator
* set_status_cb: the change operation will in this callback
*
* NOTE: The actions to modify the state must be in order.
* like: FDB_TSL_WRITE -> FDB_TSL_USER_STATUS1 -> FDB_TSL_DELETED -> FDB_TSL_USER_STATUS2
* The intermediate states can also be ignored.
* such as: FDB_TSL_WRITE -> FDB_TSL_DELETED
*/
fdb_tsl_iter(tsdb, set_status_cb, tsdb);
}
FDB_INFO("===========================================================\n");
}
static bool query_cb(fdb_tsl_t tsl, void *arg)
{
struct fdb_blob blob;
struct env_status status;
fdb_tsdb_t db = arg;
fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status))));
FDB_INFO("[query_cb] queried a TSL: time: %" __PRITS ", temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
return false;
}
static bool query_by_time_cb(fdb_tsl_t tsl, void *arg)
{
struct fdb_blob blob;
struct env_status status;
fdb_tsdb_t db = arg;
fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status))));
FDB_INFO("[query_by_time_cb] queried a TSL: time: %" __PRITS ", temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
return false;
}
static bool set_status_cb(fdb_tsl_t tsl, void *arg)
{
fdb_tsdb_t db = arg;
FDB_INFO("set the TSL (time %" __PRITS ") status from %d to %d\n", tsl->time, tsl->status, FDB_TSL_USER_STATUS1);
fdb_tsl_set_status(db, tsl, FDB_TSL_USER_STATUS1);
return false;
}
#endif /* FDB_USING_TSDB */

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#include <fal.h>
static uint8_t init_ok = 0;
/**
* FAL (Flash Abstraction Layer) initialization.
* It will initialize all flash device and all flash partition.
*
* @return >= 0: partitions total number
*/
int fal_init(void)
{
extern int fal_flash_init(void);
extern int fal_partition_init(void);
int result;
/* initialize all flash device on FAL flash table */
result = fal_flash_init();
if (result < 0) {
goto __exit;
}
/* initialize all flash partition on FAL partition table */
result = fal_partition_init();
__exit:
if ((result > 0) && (!init_ok))
{
init_ok = 1;
log_i("Flash Abstraction Layer (V%s) initialize success.", FAL_SW_VERSION);
}
else if(result <= 0)
{
init_ok = 0;
log_e("Flash Abstraction Layer (V%s) initialize failed.", FAL_SW_VERSION);
}
return result;
}
/**
* Check if the FAL is initialized successfully
*
* @return 0: not init or init failed; 1: init success
*/
int fal_init_check(void)
{
return init_ok;
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#ifndef _FAL_H_
#define _FAL_H_
#include <fal_cfg.h>
#include "fal_def.h"
/**
* FAL (Flash Abstraction Layer) initialization.
* It will initialize all flash device and all flash partition.
*
* @return >= 0: partitions total number
*/
int fal_init(void);
/* =============== flash device operator API =============== */
/**
* find flash device by name
*
* @param name flash device name
*
* @return != NULL: flash device
* NULL: not found
*/
const struct fal_flash_dev *fal_flash_device_find(const char *name);
/* =============== partition operator API =============== */
/**
* find the partition by name
*
* @param name partition name
*
* @return != NULL: partition
* NULL: not found
*/
const struct fal_partition *fal_partition_find(const char *name);
/**
* get the partition table
*
* @param len return the partition table length
*
* @return partition table
*/
const struct fal_partition *fal_get_partition_table(size_t *len);
/**
* set partition table temporarily
* This setting will modify the partition table temporarily, the setting will be lost after restart.
*
* @param table partition table
* @param len partition table length
*/
void fal_set_partition_table_temp(struct fal_partition *table, size_t len);
/**
* read data from partition
*
* @param part partition
* @param addr relative address for partition
* @param buf read buffer
* @param size read size
*
* @return >= 0: successful read data size
* -1: error
*/
int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size);
/**
* write data to partition
*
* @param part partition
* @param addr relative address for partition
* @param buf write buffer
* @param size write size
*
* @return >= 0: successful write data size
* -1: error
*/
int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size);
/**
* erase partition data
*
* @param part partition
* @param addr relative address for partition
* @param size erase size
*
* @return >= 0: successful erased data size
* -1: error
*/
int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size);
/**
* erase partition all data
*
* @param part partition
*
* @return >= 0: successful erased data size
* -1: error
*/
int fal_partition_erase_all(const struct fal_partition *part);
/**
* print the partition table
*/
void fal_show_part_table(void);
/* =============== API provided to RT-Thread =============== */
/**
* create RT-Thread block device by specified partition
*
* @param parition_name partition name
*
* @return != NULL: created block device
* NULL: created failed
*/
struct rt_device *fal_blk_device_create(const char *parition_name);
#if defined(RT_USING_MTD_NOR)
/**
* create RT-Thread MTD NOR device by specified partition
*
* @param parition_name partition name
*
* @return != NULL: created MTD NOR device
* NULL: created failed
*/
struct rt_device *fal_mtd_nor_device_create(const char *parition_name);
#endif /* defined(RT_USING_MTD_NOR) */
/**
* create RT-Thread char device by specified partition
*
* @param parition_name partition name
*
* @return != NULL: created char device
* NULL: created failed
*/
struct rt_device *fal_char_device_create(const char *parition_name);
#endif /* _FAL_H_ */

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include "eeprom_m95.h"
#include "eeprom_fm24.h"
#include "flash.h"
#define FAL_PART_HAS_TABLE_CFG
#define FAL_ERASE_SIZE 100
// 需要块大小为2的N次方
#define EEPROM_M95_1_BLOCK_SIZE M95_PAGE_SIZE_256 * 32
#define EEPROM_M95_2_BLOCK_SIZE M95_PAGE_SIZE_256 * 32
#define EEPROM_FM24_BLOCK_SIZE FM24_PAGE_SIZE * 16
#define EEPROM_M95_1_SIZE _M95M02_
#define EEPROM_M95_2_SIZE _M95M02_
#define EEPROM_FM24_SIZE FM24_SIZE
#define EEPROM_M95_1_DEV_NAME "eeprom_m95_1"
#define EEPROM_M95_2_DEV_NAME "eeprom_m95_2"
#define EEPROM_FM24_DEV_NAME "eeprom_fm24"
/* ===================== Flash device Configuration ========================= */
extern struct fal_flash_dev eeprom_m95_1;
extern struct fal_flash_dev eeprom_m95_2;
extern struct fal_flash_dev eeprom_fm24;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&eeprom_m95_1, \
&eeprom_m95_2, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
// issues :https://github.com/armink/FlashDB/issues/40 ;epprom的扇区太小
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "KVDB", EEPROM_M95_1_DEV_NAME, 0, EEPROM_M95_1_SIZE, 0}, \
{FAL_PART_MAGIC_WORD, "TSDB", EEPROM_M95_2_DEV_NAME, 0, EEPROM_M95_2_SIZE, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#ifndef _FAL_DEF_H_
#define _FAL_DEF_H_
#include <stdint.h>
#include <stdio.h>
#ifdef FDB_USING_NATIVE_ASSERT
#include <assert.h>
#endif
#define FAL_SW_VERSION "0.5.99"
#ifdef __RTTHREAD__ /* for RT-Thread platform */
#include <rtthread.h>
#define FAL_PRINTF rt_kprintf
#define FAL_MALLOC rt_malloc
#define FAL_CALLOC rt_calloc
#define FAL_REALLOC rt_realloc
#define FAL_FREE rt_free
#endif
#ifndef FAL_MALLOC
#define FAL_MALLOC malloc
#endif
#ifndef FAL_CALLOC
#define FAL_CALLOC calloc
#endif
#ifndef FAL_REALLOC
#define FAL_REALLOC realloc
#endif
#ifndef FAL_FREE
#define FAL_FREE free
#endif
#ifndef FAL_PRINTF
#define FAL_PRINTF printf
#endif
#ifndef FAL_DEBUG
#define FAL_DEBUG 0
#endif
#if FAL_DEBUG
#ifndef FDB_USING_NATIVE_ASSERT
#ifdef assert
#undef assert
#endif
#define assert(EXPR) \
if (!(EXPR)) \
{ \
FAL_PRINTF("(%s) has assert failed at %s.\n", #EXPR, __func__ ); \
while (1); \
}
#endif
/* debug level log */
#ifdef log_d
#undef log_d
#endif
#include <inttypes.h>
#define log_d(...) FAL_PRINTF("[D/FAL] (%s:%" PRIdLEAST16 ") ", __func__, __LINE__); FAL_PRINTF(__VA_ARGS__);FAL_PRINTF("\n")
#else
#ifndef FDB_USING_NATIVE_ASSERT
#ifdef assert
#undef assert
#endif
#define assert(EXPR) ((void)0);
#endif
/* debug level log */
#ifdef log_d
#undef log_d
#endif
#define log_d(...)
#endif /* FAL_DEBUG */
/* error level log */
#ifdef log_e
#undef log_e
#endif
#define log_e(...) FAL_PRINTF("\033[31;22m[E/FAL] (%s:%d) ", __func__, __LINE__);FAL_PRINTF(__VA_ARGS__);FAL_PRINTF("\033[0m\n")
/* info level log */
#ifdef log_i
#undef log_i
#endif
#define log_i(...) FAL_PRINTF("\033[32;22m[I/FAL] "); FAL_PRINTF(__VA_ARGS__);FAL_PRINTF("\033[0m\n")
/* FAL flash and partition device name max length */
#ifndef FAL_DEV_NAME_MAX
#define FAL_DEV_NAME_MAX 24
#endif
struct fal_flash_dev
{
char name[FAL_DEV_NAME_MAX];
/* flash device start address and len */
uint32_t addr;
size_t len;
/* the block size in the flash for erase minimum granularity */
size_t blk_size;
struct
{
int (*init)(void);
int (*read)(long offset, uint8_t *buf, size_t size);
int (*write)(long offset, const uint8_t *buf, size_t size);
int (*erase)(long offset, size_t size);
} ops;
/* write minimum granularity, unit: bit.
1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1)/ 64(stm32l4)
0 will not take effect. */
size_t write_gran;
};
typedef struct fal_flash_dev *fal_flash_dev_t;
/**
* FAL partition
*/
struct fal_partition
{
uint32_t magic_word;
/* partition name */
char name[FAL_DEV_NAME_MAX];
/* flash device name for partition */
char flash_name[FAL_DEV_NAME_MAX];
/* partition offset address on flash device */
long offset;
size_t len;
uint32_t reserved;
};
typedef struct fal_partition *fal_partition_t;
#endif /* _FAL_DEF_H_ */

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#include <fal.h>
#include <string.h>
/* flash device table, must defined by user */
#if !defined(FAL_FLASH_DEV_TABLE)
#error "You must defined flash device table (FAL_FLASH_DEV_TABLE) on 'fal_cfg.h'"
#endif
static const struct fal_flash_dev * const device_table[] = FAL_FLASH_DEV_TABLE;
static const size_t device_table_len = sizeof(device_table) / sizeof(device_table[0]);
static uint8_t init_ok = 0;
/**
* Initialize all flash device on FAL flash table
*
* @return result
*/
int fal_flash_init(void)
{
size_t i;
if (init_ok)
{
return 0;
}
for (i = 0; i < device_table_len; i++)
{
assert(device_table[i]->ops.read);
assert(device_table[i]->ops.write);
assert(device_table[i]->ops.erase);
/* init flash device on flash table */
if (device_table[i]->ops.init)
{
device_table[i]->ops.init();
}
log_d("Flash device | %*.*s | addr: 0x%08lx | len: 0x%08x | blk_size: 0x%08x |initialized finish.",
FAL_DEV_NAME_MAX, FAL_DEV_NAME_MAX, device_table[i]->name, device_table[i]->addr, device_table[i]->len,
device_table[i]->blk_size);
}
init_ok = 1;
return 0;
}
/**
* find flash device by name
*
* @param name flash device name
*
* @return != NULL: flash device
* NULL: not found
*/
const struct fal_flash_dev *fal_flash_device_find(const char *name)
{
assert(init_ok);
assert(name);
size_t i;
for (i = 0; i < device_table_len; i++)
{
if (!strncmp(name, device_table[i]->name, FAL_DEV_NAME_MAX)) {
return device_table[i];
}
}
return NULL;
}

View File

@ -0,0 +1,525 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-17 armink the first version
*/
#include <fal.h>
#include <string.h>
#include <stdlib.h>
/* partition magic word */
#define FAL_PART_MAGIC_WORD 0x45503130
#define FAL_PART_MAGIC_WORD_H 0x4550L
#define FAL_PART_MAGIC_WORD_L 0x3130L
struct part_flash_info
{
const struct fal_flash_dev *flash_dev;
};
/**
* FAL partition table config has defined on 'fal_cfg.h'.
* When this option is disable, it will auto find the partition table on a specified location in flash partition.
*/
#ifdef FAL_PART_HAS_TABLE_CFG
/* check partition table definition */
#if !defined(FAL_PART_TABLE)
#error "You must defined FAL_PART_TABLE on 'fal_cfg.h'"
#endif
#ifdef __CC_ARM /* ARM Compiler */
#define SECTION(x) __attribute__((section(x)))
#define USED __attribute__((used))
#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
#define SECTION(x) @ x
#define USED __root
#elif defined (__GNUC__) /* GNU GCC Compiler */
#define SECTION(x) __attribute__((section(x)))
#define USED __attribute__((used))
#else
#error not supported tool chain
#endif /* __CC_ARM */
//USED static const struct fal_partition partition_table_def[] SECTION("FalPartTable") = FAL_PART_TABLE;
static const struct fal_partition partition_table_def[] = FAL_PART_TABLE;
static const struct fal_partition *partition_table = NULL;
/* partition and flash object information cache table */
static struct part_flash_info part_flash_cache[sizeof(partition_table_def) / sizeof(partition_table_def[0])] = { 0 };
#else /* FAL_PART_HAS_TABLE_CFG */
#if !defined(FAL_PART_TABLE_FLASH_DEV_NAME)
#error "You must defined FAL_PART_TABLE_FLASH_DEV_NAME on 'fal_cfg.h'"
#endif
/* check partition table end offset address definition */
#if !defined(FAL_PART_TABLE_END_OFFSET)
#error "You must defined FAL_PART_TABLE_END_OFFSET on 'fal_cfg.h'"
#endif
static struct fal_partition *partition_table = NULL;
static struct part_flash_info *part_flash_cache = NULL;
#endif /* FAL_PART_HAS_TABLE_CFG */
static uint8_t init_ok = 0;
static size_t partition_table_len = 0;
/**
* print the partition table
*/
void fal_show_part_table(void)
{
char *item1 = "name", *item2 = "flash_dev";
size_t i, part_name_max = strlen(item1), flash_dev_name_max = strlen(item2);
const struct fal_partition *part;
if (partition_table_len)
{
for (i = 0; i < partition_table_len; i++)
{
part = &partition_table[i];
if (strlen(part->name) > part_name_max)
{
part_name_max = strlen(part->name);
}
if (strlen(part->flash_name) > flash_dev_name_max)
{
flash_dev_name_max = strlen(part->flash_name);
}
}
}
log_i("==================== FAL partition table ====================");
log_i("| %-*.*s | %-*.*s | offset | length |", part_name_max, FAL_DEV_NAME_MAX, item1, flash_dev_name_max,
FAL_DEV_NAME_MAX, item2);
log_i("-------------------------------------------------------------");
for (i = 0; i < partition_table_len; i++)
{
#ifdef FAL_PART_HAS_TABLE_CFG
part = &partition_table[i];
#else
part = &partition_table[partition_table_len - i - 1];
#endif
log_i("| %-*.*s | %-*.*s | 0x%08lx | 0x%08x |", part_name_max, FAL_DEV_NAME_MAX, part->name, flash_dev_name_max,
FAL_DEV_NAME_MAX, part->flash_name, part->offset, part->len);
}
log_i("=============================================================");
}
static int check_and_update_part_cache(const struct fal_partition *table, size_t len)
{
const struct fal_flash_dev *flash_dev = NULL;
size_t i;
#ifndef FAL_PART_HAS_TABLE_CFG
if (part_flash_cache)
{
FAL_FREE(part_flash_cache);
}
part_flash_cache = FAL_MALLOC(len * sizeof(struct part_flash_info));
if (part_flash_cache == NULL)
{
log_e("Initialize failed! No memory for partition table cache");
return -2;
}
#endif
for (i = 0; i < len; i++)
{
flash_dev = fal_flash_device_find(table[i].flash_name);
if (flash_dev == NULL)
{
log_d("Warning: Do NOT found the flash device(%s).", table[i].flash_name);
continue;
}
if (table[i].offset >= (long)flash_dev->len)
{
log_e("Initialize failed! Partition(%s) offset address(%ld) out of flash bound(<%d).",
table[i].name, table[i].offset, flash_dev->len);
partition_table_len = 0;
return -1;
}
part_flash_cache[i].flash_dev = flash_dev;
}
return 0;
}
/**
* Initialize all flash partition on FAL partition table
*
* @return partitions total number
*/
int fal_partition_init(void)
{
if (init_ok)
{
return partition_table_len;
}
#ifdef FAL_PART_HAS_TABLE_CFG
partition_table = &partition_table_def[0];
partition_table_len = sizeof(partition_table_def) / sizeof(partition_table_def[0]);
#else
/* load partition table from the end address FAL_PART_TABLE_END_OFFSET, error return 0 */
long part_table_offset = FAL_PART_TABLE_END_OFFSET;
size_t table_num = 0, table_item_size = 0;
uint8_t part_table_find_ok = 0;
uint32_t read_magic_word;
fal_partition_t new_part = NULL;
size_t i;
const struct fal_flash_dev *flash_dev = NULL;
flash_dev = fal_flash_device_find(FAL_PART_TABLE_FLASH_DEV_NAME);
if (flash_dev == NULL)
{
log_e("Initialize failed! Flash device (%s) NOT found.", FAL_PART_TABLE_FLASH_DEV_NAME);
goto _exit;
}
/* check partition table offset address */
if (part_table_offset < 0 || part_table_offset >= (long) flash_dev->len)
{
log_e("Setting partition table end offset address(%ld) out of flash bound(<%d).", part_table_offset, flash_dev->len);
goto _exit;
}
table_item_size = sizeof(struct fal_partition);
new_part = (fal_partition_t)FAL_MALLOC(table_item_size);
if (new_part == NULL)
{
log_e("Initialize failed! No memory for table buffer.");
goto _exit;
}
/* find partition table location */
{
uint8_t read_buf[64];
part_table_offset -= sizeof(read_buf);
while (part_table_offset >= 0)
{
if (flash_dev->ops.read(part_table_offset, read_buf, sizeof(read_buf)) > 0)
{
/* find magic word in read buf */
for (i = 0; i < sizeof(read_buf) - sizeof(read_magic_word) + 1; i++)
{
read_magic_word = read_buf[0 + i] + (read_buf[1 + i] << 8) + (read_buf[2 + i] << 16) + (read_buf[3 + i] << 24);
if (read_magic_word == ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
{
part_table_find_ok = 1;
part_table_offset += i;
log_d("Find the partition table on '%s' offset @0x%08lx.", FAL_PART_TABLE_FLASH_DEV_NAME,
part_table_offset);
break;
}
}
}
else
{
/* read failed */
break;
}
if (part_table_find_ok)
{
break;
}
else
{
/* calculate next read buf position */
if (part_table_offset >= (long)sizeof(read_buf))
{
part_table_offset -= sizeof(read_buf);
part_table_offset += (sizeof(read_magic_word) - 1);
}
else if (part_table_offset != 0)
{
part_table_offset = 0;
}
else
{
/* find failed */
break;
}
}
}
}
/* load partition table */
while (part_table_find_ok)
{
memset(new_part, 0x00, table_num);
if (flash_dev->ops.read(part_table_offset - table_item_size * (table_num), (uint8_t *) new_part,
table_item_size) < 0)
{
log_e("Initialize failed! Flash device (%s) read error!", flash_dev->name);
table_num = 0;
break;
}
if (new_part->magic_word != ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
{
break;
}
partition_table = (fal_partition_t) FAL_REALLOC(partition_table, table_item_size * (table_num + 1));
if (partition_table == NULL)
{
log_e("Initialize failed! No memory for partition table");
table_num = 0;
break;
}
memcpy(partition_table + table_num, new_part, table_item_size);
table_num++;
};
if (table_num == 0)
{
log_e("Partition table NOT found on flash: %s (len: %d) from offset: 0x%08x.", FAL_PART_TABLE_FLASH_DEV_NAME,
FAL_DEV_NAME_MAX, FAL_PART_TABLE_END_OFFSET);
goto _exit;
}
else
{
partition_table_len = table_num;
}
#endif /* FAL_PART_HAS_TABLE_CFG */
/* check the partition table device exists */
if (check_and_update_part_cache(partition_table, partition_table_len) != 0)
{
goto _exit;
}
init_ok = 1;
_exit:
#if FAL_DEBUG
fal_show_part_table();
#endif
#ifndef FAL_PART_HAS_TABLE_CFG
if (new_part)
{
FAL_FREE(new_part);
}
#endif /* !FAL_PART_HAS_TABLE_CFG */
return partition_table_len;
}
/**
* find the partition by name
*
* @param name partition name
*
* @return != NULL: partition
* NULL: not found
*/
const struct fal_partition *fal_partition_find(const char *name)
{
assert(init_ok);
size_t i;
for (i = 0; i < partition_table_len; i++)
{
if (!strcmp(name, partition_table[i].name))
{
return &partition_table[i];
}
}
return NULL;
}
static const struct fal_flash_dev *flash_device_find_by_part(const struct fal_partition *part)
{
assert(part >= partition_table);
assert(part <= &partition_table[partition_table_len - 1]);
return part_flash_cache[part - partition_table].flash_dev;
}
/**
* get the partition table
*
* @param len return the partition table length
*
* @return partition table
*/
const struct fal_partition *fal_get_partition_table(size_t *len)
{
assert(init_ok);
assert(len);
*len = partition_table_len;
return partition_table;
}
/**
* set partition table temporarily
* This setting will modify the partition table temporarily, the setting will be lost after restart.
*
* @param table partition table
* @param len partition table length
*/
void fal_set_partition_table_temp(struct fal_partition *table, size_t len)
{
assert(init_ok);
assert(table);
check_and_update_part_cache(table, len);
partition_table_len = len;
partition_table = table;
}
/**
* read data from partition
*
* @param part partition
* @param addr relative address for partition
* @param buf read buffer
* @param size read size
*
* @return >= 0: successful read data size
* -1: error
*/
int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
{
int ret = 0;
const struct fal_flash_dev *flash_dev = NULL;
assert(part);
assert(buf);
if (addr + size > part->len)
{
log_e("Partition read error! Partition address out of bound.");
return -1;
}
flash_dev = flash_device_find_by_part(part);
if (flash_dev == NULL)
{
log_e("Partition read error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
return -1;
}
ret = flash_dev->ops.read(part->offset + addr, buf, size);
if (ret < 0)
{
log_e("Partition read error! Flash device(%s) read error!", part->flash_name);
}
return ret;
}
/**
* write data to partition
*
* @param part partition
* @param addr relative address for partition
* @param buf write buffer
* @param size write size
*
* @return >= 0: successful write data size
* -1: error
*/
int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
{
int ret = 0;
const struct fal_flash_dev *flash_dev = NULL;
assert(part);
assert(buf);
if (addr + size > part->len)
{
log_e("Partition write error! Partition address out of bound.");
return -1;
}
flash_dev = flash_device_find_by_part(part);
if (flash_dev == NULL)
{
log_e("Partition write error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
return -1;
}
ret = flash_dev->ops.write(part->offset + addr, buf, size);
if (ret < 0)
{
log_e("Partition write error! Flash device(%s) write error!", part->flash_name);
}
return ret;
}
/**
* erase partition data
*
* @param part partition
* @param addr relative address for partition
* @param size erase size
*
* @return >= 0: successful erased data size
* -1: error
*/
int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
{
int ret = 0;
const struct fal_flash_dev *flash_dev = NULL;
assert(part);
if (addr + size > part->len)
{
log_e("Partition erase error! Partition address out of bound.");
return -1;
}
flash_dev = flash_device_find_by_part(part);
if (flash_dev == NULL)
{
log_e("Partition erase error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
return -1;
}
ret = flash_dev->ops.erase(part->offset + addr, size);
if (ret < 0)
{
log_e("Partition erase error! Flash device(%s) erase error!", part->flash_name);
}
return ret;
}
/**
* erase partition all data
*
* @param part partition
*
* @return >= 0: successful erased data size
* -1: error
*/
int fal_partition_erase_all(const struct fal_partition *part)
{
return fal_partition_erase(part, 0, part->len);
}

View File

@ -0,0 +1,934 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-06-23 armink the first version
* 2019-08-22 MurphyZhao adapt to none rt-thread case
*/
#include <fal.h>
#ifdef RT_VER_NUM
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
/* ========================== block device ======================== */
struct fal_blk_device
{
struct rt_device parent;
struct rt_device_blk_geometry geometry;
const struct fal_partition *fal_part;
};
/* RT-Thread device interface */
#if RTTHREAD_VERSION >= 30000
static rt_err_t blk_dev_control(rt_device_t dev, int cmd, void *args)
#else
static rt_err_t blk_dev_control(rt_device_t dev, rt_uint8_t cmd, void *args)
#endif
{
struct fal_blk_device *part = (struct fal_blk_device*) dev;
assert(part != RT_NULL);
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
{
struct rt_device_blk_geometry *geometry;
geometry = (struct rt_device_blk_geometry *) args;
if (geometry == RT_NULL)
{
return -RT_ERROR;
}
memcpy(geometry, &part->geometry, sizeof(struct rt_device_blk_geometry));
}
else if (cmd == RT_DEVICE_CTRL_BLK_ERASE)
{
rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
rt_size_t phy_size;
if (addrs == RT_NULL || start_addr > end_addr)
{
return -RT_ERROR;
}
if (end_addr == start_addr)
{
end_addr++;
}
phy_start_addr = start_addr * part->geometry.bytes_per_sector;
phy_size = (end_addr - start_addr) * part->geometry.bytes_per_sector;
if (fal_partition_erase(part->fal_part, phy_start_addr, phy_size) < 0)
{
return -RT_ERROR;
}
}
return RT_EOK;
}
static rt_size_t blk_dev_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{
int ret = 0;
struct fal_blk_device *part = (struct fal_blk_device*) dev;
assert(part != RT_NULL);
ret = fal_partition_read(part->fal_part, pos * part->geometry.block_size, buffer, size * part->geometry.block_size);
if (ret != (int)(size * part->geometry.block_size))
{
ret = 0;
}
else
{
ret = size;
}
return ret;
}
static rt_size_t blk_dev_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{
int ret = 0;
struct fal_blk_device *part;
rt_off_t phy_pos;
rt_size_t phy_size;
part = (struct fal_blk_device*) dev;
assert(part != RT_NULL);
/* change the block device's logic address to physical address */
phy_pos = pos * part->geometry.bytes_per_sector;
phy_size = size * part->geometry.bytes_per_sector;
ret = fal_partition_erase(part->fal_part, phy_pos, phy_size);
if (ret == (int) phy_size)
{
ret = fal_partition_write(part->fal_part, phy_pos, buffer, phy_size);
}
if (ret != (int) phy_size)
{
ret = 0;
}
else
{
ret = size;
}
return ret;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops blk_dev_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
blk_dev_read,
blk_dev_write,
blk_dev_control
};
#endif
/**
* create RT-Thread block device by specified partition
*
* @param parition_name partition name
*
* @return != NULL: created block device
* NULL: created failed
*/
struct rt_device *fal_blk_device_create(const char *parition_name)
{
struct fal_blk_device *blk_dev;
const struct fal_partition *fal_part = fal_partition_find(parition_name);
const struct fal_flash_dev *fal_flash = NULL;
if (!fal_part)
{
log_e("Error: the partition name (%s) is not found.", parition_name);
return NULL;
}
if ((fal_flash = fal_flash_device_find(fal_part->flash_name)) == NULL)
{
log_e("Error: the flash device name (%s) is not found.", fal_part->flash_name);
return NULL;
}
blk_dev = (struct fal_blk_device*) rt_malloc(sizeof(struct fal_blk_device));
if (blk_dev)
{
blk_dev->fal_part = fal_part;
blk_dev->geometry.bytes_per_sector = fal_flash->blk_size;
blk_dev->geometry.block_size = fal_flash->blk_size;
blk_dev->geometry.sector_count = fal_part->len / fal_flash->blk_size;
/* register device */
blk_dev->parent.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
blk_dev->parent.ops = &blk_dev_ops;
#else
blk_dev->parent.init = NULL;
blk_dev->parent.open = NULL;
blk_dev->parent.close = NULL;
blk_dev->parent.read = blk_dev_read;
blk_dev->parent.write = blk_dev_write;
blk_dev->parent.control = blk_dev_control;
#endif
/* no private */
blk_dev->parent.user_data = RT_NULL;
log_i("The FAL block device (%s) created successfully", fal_part->name);
rt_device_register(RT_DEVICE(blk_dev), fal_part->name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
}
else
{
log_e("Error: no memory for create FAL block device");
}
return RT_DEVICE(blk_dev);
}
/* ========================== MTD nor device ======================== */
#if defined(RT_USING_MTD_NOR)
struct fal_mtd_nor_device
{
struct rt_mtd_nor_device parent;
const struct fal_partition *fal_part;
};
static rt_size_t mtd_nor_dev_read(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_uint32_t length)
{
int ret = 0;
struct fal_mtd_nor_device *part = (struct fal_mtd_nor_device*) device;
assert(part != RT_NULL);
ret = fal_partition_read(part->fal_part, offset, data, length);
if (ret != (int)length)
{
ret = 0;
}
else
{
ret = length;
}
return ret;
}
static rt_size_t mtd_nor_dev_write(struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length)
{
int ret = 0;
struct fal_mtd_nor_device *part;
part = (struct fal_mtd_nor_device*) device;
assert(part != RT_NULL);
ret = fal_partition_write(part->fal_part, offset, data, length);
if (ret != (int) length)
{
ret = 0;
}
else
{
ret = length;
}
return ret;
}
static rt_err_t mtd_nor_dev_erase(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint32_t length)
{
int ret = 0;
struct fal_mtd_nor_device *part;
part = (struct fal_mtd_nor_device*) device;
assert(part != RT_NULL);
ret = fal_partition_erase(part->fal_part, offset, length);
if (ret != length)
{
return -RT_ERROR;
}
else
{
return RT_EOK;
}
}
static const struct rt_mtd_nor_driver_ops _ops =
{
RT_NULL,
mtd_nor_dev_read,
mtd_nor_dev_write,
mtd_nor_dev_erase,
};
/**
* create RT-Thread MTD NOR device by specified partition
*
* @param parition_name partition name
*
* @return != NULL: created MTD NOR device
* NULL: created failed
*/
struct rt_device *fal_mtd_nor_device_create(const char *parition_name)
{
struct fal_mtd_nor_device *mtd_nor_dev;
const struct fal_partition *fal_part = fal_partition_find(parition_name);
const struct fal_flash_dev *fal_flash = NULL;
if (!fal_part)
{
log_e("Error: the partition name (%s) is not found.", parition_name);
return NULL;
}
if ((fal_flash = fal_flash_device_find(fal_part->flash_name)) == NULL)
{
log_e("Error: the flash device name (%s) is not found.", fal_part->flash_name);
return NULL;
}
mtd_nor_dev = (struct fal_mtd_nor_device*) rt_malloc(sizeof(struct fal_mtd_nor_device));
if (mtd_nor_dev)
{
mtd_nor_dev->fal_part = fal_part;
mtd_nor_dev->parent.block_start = 0;
mtd_nor_dev->parent.block_end = fal_part->len / fal_flash->blk_size;
mtd_nor_dev->parent.block_size = fal_flash->blk_size;
/* set ops */
mtd_nor_dev->parent.ops = &_ops;
log_i("The FAL MTD NOR device (%s) created successfully", fal_part->name);
rt_mtd_nor_register_device(fal_part->name, &mtd_nor_dev->parent);
}
else
{
log_e("Error: no memory for create FAL MTD NOR device");
}
return RT_DEVICE(&mtd_nor_dev->parent);
}
#endif /* defined(RT_USING_MTD_NOR) */
/* ========================== char device ======================== */
struct fal_char_device
{
struct rt_device parent;
const struct fal_partition *fal_part;
};
/* RT-Thread device interface */
static rt_size_t char_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
int ret = 0;
struct fal_char_device *part = (struct fal_char_device *) dev;
assert(part != RT_NULL);
if (pos + size > part->fal_part->len)
size = part->fal_part->len - pos;
ret = fal_partition_read(part->fal_part, pos, buffer, size);
if (ret != (int)(size))
ret = 0;
return ret;
}
static rt_size_t char_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
int ret = 0;
struct fal_char_device *part;
part = (struct fal_char_device *) dev;
assert(part != RT_NULL);
if (pos == 0)
{
fal_partition_erase_all(part->fal_part);
}
else if (pos + size > part->fal_part->len)
{
size = part->fal_part->len - pos;
}
ret = fal_partition_write(part->fal_part, pos, buffer, size);
if (ret != (int) size)
ret = 0;
return ret;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops char_dev_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
char_dev_read,
char_dev_write,
RT_NULL
};
#endif
#ifdef RT_USING_POSIX
#include <dfs_posix.h>
/* RT-Thread device filesystem interface */
static int char_dev_fopen(struct dfs_fd *fd)
{
struct fal_char_device *part = (struct fal_char_device *) fd->data;
assert(part != RT_NULL);
switch (fd->flags & O_ACCMODE)
{
case O_RDONLY:
break;
case O_WRONLY:
case O_RDWR:
/* erase partition when device file open */
fal_partition_erase_all(part->fal_part);
break;
default:
break;
}
fd->pos = 0;
return RT_EOK;
}
static int char_dev_fread(struct dfs_fd *fd, void *buf, size_t count)
{
int ret = 0;
struct fal_char_device *part = (struct fal_char_device *) fd->data;
assert(part != RT_NULL);
if (fd->pos + count > part->fal_part->len)
count = part->fal_part->len - fd->pos;
ret = fal_partition_read(part->fal_part, fd->pos, buf, count);
if (ret != (int)(count))
return 0;
fd->pos += ret;
return ret;
}
static int char_dev_fwrite(struct dfs_fd *fd, const void *buf, size_t count)
{
int ret = 0;
struct fal_char_device *part = (struct fal_char_device *) fd->data;
assert(part != RT_NULL);
if (fd->pos + count > part->fal_part->len)
count = part->fal_part->len - fd->pos;
ret = fal_partition_write(part->fal_part, fd->pos, buf, count);
if (ret != (int) count)
return 0;
fd->pos += ret;
return ret;
}
static const struct dfs_file_ops char_dev_fops =
{
char_dev_fopen,
RT_NULL,
RT_NULL,
char_dev_fread,
char_dev_fwrite,
RT_NULL, /* flush */
RT_NULL, /* lseek */
RT_NULL, /* getdents */
RT_NULL,
};
#endif /* defined(RT_USING_POSIX) */
/**
* create RT-Thread char device by specified partition
*
* @param parition_name partition name
*
* @return != NULL: created char device
* NULL: created failed
*/
struct rt_device *fal_char_device_create(const char *parition_name)
{
struct fal_char_device *char_dev;
const struct fal_partition *fal_part = fal_partition_find(parition_name);
if (!fal_part)
{
log_e("Error: the partition name (%s) is not found.", parition_name);
return NULL;
}
if ((fal_flash_device_find(fal_part->flash_name)) == NULL)
{
log_e("Error: the flash device name (%s) is not found.", fal_part->flash_name);
return NULL;
}
char_dev = (struct fal_char_device *) rt_malloc(sizeof(struct fal_char_device));
if (char_dev)
{
char_dev->fal_part = fal_part;
/* register device */
char_dev->parent.type = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
char_dev->parent.ops = &char_dev_ops;
#else
char_dev->parent.init = NULL;
char_dev->parent.open = NULL;
char_dev->parent.close = NULL;
char_dev->parent.read = char_dev_read;
char_dev->parent.write = char_dev_write;
char_dev->parent.control = NULL;
/* no private */
char_dev->parent.user_data = NULL;
#endif
rt_device_register(RT_DEVICE(char_dev), fal_part->name, RT_DEVICE_FLAG_RDWR);
log_i("The FAL char device (%s) created successfully", fal_part->name);
#ifdef RT_USING_POSIX
/* set fops */
char_dev->parent.fops = &char_dev_fops;
#endif
}
else
{
log_e("Error: no memory for create FAL char device");
}
return RT_DEVICE(char_dev);
}
#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
#include <finsh.h>
extern int fal_init_check(void);
static void fal(uint8_t argc, char **argv) {
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
#define HEXDUMP_WIDTH 16
#define CMD_PROBE_INDEX 0
#define CMD_READ_INDEX 1
#define CMD_WRITE_INDEX 2
#define CMD_ERASE_INDEX 3
#define CMD_BENCH_INDEX 4
int result;
static const struct fal_flash_dev *flash_dev = NULL;
static const struct fal_partition *part_dev = NULL;
size_t i = 0, j = 0;
const char* help_info[] =
{
[CMD_PROBE_INDEX] = "fal probe [dev_name|part_name] - probe flash device or partition by given name",
[CMD_READ_INDEX] = "fal read addr size - read 'size' bytes starting at 'addr'",
[CMD_WRITE_INDEX] = "fal write addr data1 ... dataN - write some bytes 'data' starting at 'addr'",
[CMD_ERASE_INDEX] = "fal erase addr size - erase 'size' bytes starting at 'addr'",
[CMD_BENCH_INDEX] = "fal bench <blk_size> - benchmark test with per block size",
};
if (fal_init_check() != 1)
{
rt_kprintf("\n[Warning] FAL is not initialized or failed to initialize!\n\n");
return;
}
if (argc < 2)
{
rt_kprintf("Usage:\n");
for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
{
rt_kprintf("%s\n", help_info[i]);
}
rt_kprintf("\n");
}
else
{
const char *operator = argv[1];
uint32_t addr, size;
if (!strcmp(operator, "probe"))
{
if (argc >= 3)
{
char *dev_name = argv[2];
if ((flash_dev = fal_flash_device_find(dev_name)) != NULL)
{
part_dev = NULL;
}
else if ((part_dev = fal_partition_find(dev_name)) != NULL)
{
flash_dev = NULL;
}
else
{
rt_kprintf("Device %s NOT found. Probe failed.\n", dev_name);
flash_dev = NULL;
part_dev = NULL;
}
}
if (flash_dev)
{
rt_kprintf("Probed a flash device | %s | addr: %ld | len: %d |.\n", flash_dev->name,
flash_dev->addr, flash_dev->len);
}
else if (part_dev)
{
rt_kprintf("Probed a flash partition | %s | flash_dev: %s | offset: %ld | len: %d |.\n",
part_dev->name, part_dev->flash_name, part_dev->offset, part_dev->len);
}
else
{
rt_kprintf("No flash device or partition was probed.\n");
rt_kprintf("Usage: %s.\n", help_info[CMD_PROBE_INDEX]);
fal_show_part_table();
}
}
else
{
if (!flash_dev && !part_dev)
{
rt_kprintf("No flash device or partition was probed. Please run 'fal probe'.\n");
return;
}
if (!rt_strcmp(operator, "read"))
{
if (argc < 4)
{
rt_kprintf("Usage: %s.\n", help_info[CMD_READ_INDEX]);
return;
}
else
{
addr = strtol(argv[2], NULL, 0);
size = strtol(argv[3], NULL, 0);
uint8_t *data = rt_malloc(size);
if (data)
{
if (flash_dev)
{
result = flash_dev->ops.read(addr, data, size);
}
else if (part_dev)
{
result = fal_partition_read(part_dev, addr, data, size);
}
if (result >= 0)
{
rt_kprintf("Read data success. Start from 0x%08X, size is %ld. The data is:\n", addr,
size);
rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
for (i = 0; i < size; i += HEXDUMP_WIDTH)
{
rt_kprintf("[%08X] ", addr + i);
/* dump hex */
for (j = 0; j < HEXDUMP_WIDTH; j++)
{
if (i + j < size)
{
rt_kprintf("%02X ", data[i + j]);
}
else
{
rt_kprintf(" ");
}
}
/* dump char for hex */
for (j = 0; j < HEXDUMP_WIDTH; j++)
{
if (i + j < size)
{
rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
}
}
rt_kprintf("\n");
}
rt_kprintf("\n");
}
rt_free(data);
}
else
{
rt_kprintf("Low memory!\n");
}
}
}
else if (!strcmp(operator, "write"))
{
if (argc < 4)
{
rt_kprintf("Usage: %s.\n", help_info[CMD_WRITE_INDEX]);
return;
}
else
{
addr = strtol(argv[2], NULL, 0);
size = argc - 3;
uint8_t *data = rt_malloc(size);
if (data)
{
for (i = 0; i < size; i++)
{
data[i] = strtol(argv[3 + i], NULL, 0);
}
if (flash_dev)
{
result = flash_dev->ops.write(addr, data, size);
}
else if (part_dev)
{
result = fal_partition_write(part_dev, addr, data, size);
}
if (result >= 0)
{
rt_kprintf("Write data success. Start from 0x%08X, size is %ld.\n", addr, size);
rt_kprintf("Write data: ");
for (i = 0; i < size; i++)
{
rt_kprintf("%d ", data[i]);
}
rt_kprintf(".\n");
}
rt_free(data);
}
else
{
rt_kprintf("Low memory!\n");
}
}
}
else if (!rt_strcmp(operator, "erase"))
{
if (argc < 4)
{
rt_kprintf("Usage: %s.\n", help_info[CMD_ERASE_INDEX]);
return;
}
else
{
addr = strtol(argv[2], NULL, 0);
size = strtol(argv[3], NULL, 0);
if (flash_dev)
{
result = flash_dev->ops.erase(addr, size);
}
else if (part_dev)
{
result = fal_partition_erase(part_dev, addr, size);
}
if (result >= 0)
{
rt_kprintf("Erase data success. Start from 0x%08X, size is %ld.\n", addr, size);
}
}
}
else if (!strcmp(operator, "bench"))
{
if (argc < 3)
{
rt_kprintf("Usage: %s.\n", help_info[CMD_BENCH_INDEX]);
return;
}
else if ((argc > 3 && strcmp(argv[3], "yes")) || argc < 4)
{
rt_kprintf("DANGER: It will erase full chip or partition! Please run 'fal bench %d yes'.\n", strtol(argv[2], NULL, 0));
return;
}
/* full chip benchmark test */
uint32_t start_time, time_cast;
size_t write_size = strtol(argv[2], NULL, 0), read_size = strtol(argv[2], NULL, 0), cur_op_size;
uint8_t *write_data = (uint8_t *)rt_malloc(write_size), *read_data = (uint8_t *)rt_malloc(read_size);
if (write_data && read_data)
{
for (i = 0; i < write_size; i ++) {
write_data[i] = i & 0xFF;
}
if (flash_dev)
{
size = flash_dev->len;
}
else if (part_dev)
{
size = part_dev->len;
}
/* benchmark testing */
rt_kprintf("Erasing %ld bytes data, waiting...\n", size);
start_time = rt_tick_get();
if (flash_dev)
{
result = flash_dev->ops.erase(0, size);
}
else if (part_dev)
{
result = fal_partition_erase(part_dev, 0, size);
}
if (result >= 0)
{
time_cast = rt_tick_get() - start_time;
rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
}
else
{
rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
}
/* write test */
rt_kprintf("Writing %ld bytes data, waiting...\n", size);
start_time = rt_tick_get();
for (i = 0; i < size; i += write_size)
{
if (i + write_size <= size)
{
cur_op_size = write_size;
}
else
{
cur_op_size = size - i;
}
if (flash_dev)
{
result = flash_dev->ops.write(i, write_data, cur_op_size);
}
else if (part_dev)
{
result = fal_partition_write(part_dev, i, write_data, cur_op_size);
}
if (result < 0)
{
break;
}
}
if (result >= 0)
{
time_cast = rt_tick_get() - start_time;
rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
}
else
{
rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
}
/* read test */
rt_kprintf("Reading %ld bytes data, waiting...\n", size);
start_time = rt_tick_get();
for (i = 0; i < size; i += read_size)
{
if (i + read_size <= size)
{
cur_op_size = read_size;
}
else
{
cur_op_size = size - i;
}
if (flash_dev)
{
result = flash_dev->ops.read(i, read_data, cur_op_size);
}
else if (part_dev)
{
result = fal_partition_read(part_dev, i, read_data, cur_op_size);
}
/* data check */
for (int index = 0; index < cur_op_size; index ++)
{
if (write_data[index] != read_data[index])
{
rt_kprintf("%d %d %02x %02x.\n", i, index, write_data[index], read_data[index]);
}
}
if (memcmp(write_data, read_data, cur_op_size))
{
result = -RT_ERROR;
rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
}
/* has an error */
if (result < 0)
{
break;
}
}
if (result >= 0)
{
time_cast = rt_tick_get() - start_time;
rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
}
else
{
rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
}
}
else
{
rt_kprintf("Low memory!\n");
}
rt_free(write_data);
rt_free(read_data);
}
else
{
rt_kprintf("Usage:\n");
for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
{
rt_kprintf("%s\n", help_info[i]);
}
rt_kprintf("\n");
return;
}
if (result < 0) {
rt_kprintf("This operate has an error. Error code: %d.\n", result);
}
}
}
}
MSH_CMD_EXPORT(fal, FAL (Flash Abstraction Layer) operate.);
#endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
#endif /* RT_VER_NUM */

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-01-26 armink the first version
*/
#include "eeprom_fm24.h"
#include <fal.h>
static int init(void);
static int erase(long offset, size_t size);
static int read(long offset, uint8_t *buf, size_t size);
static int write(long offset, const uint8_t *buf, size_t size);
// 1.定义 flash 设备
struct fal_flash_dev eeprom_fm24 =
{
.name = EEPROM_FM24_DEV_NAME,
.addr = 0,
.len = FM24_PAGE_SIZE,
.blk_size = EEPROM_FM24_BLOCK_SIZE,
.ops = {init, read, write, erase},
.write_gran = 1};
static int init(void)
{
return 1;
}
static int erase(long offset, size_t size)
{
// uint8_t erase_size = size > FAL_ERASE_SIZE ? FAL_ERASE_SIZE : size;
// uint8_t buf[FAL_ERASE_SIZE];
// osel_memset(buf, 0xFF, FAL_ERASE_SIZE);
// for (uint8_t i = 0; i < (size / FM24_PAGE_SIZE); i++)
// {
// uint32_t addr = eeprom_fm24.addr + offset + i * FM24_PAGE_SIZE;
// eeprom_fm24_write(addr, (uint8_t *)buf, erase_size);
// }
return size;
}
static int read(long offset, uint8_t *buf, size_t size)
{
/* You can add your code under here. */
if (size == 0)
{
return 0;
}
uint32_t addr = eeprom_fm24.addr + offset;
BOOL res = eeprom_fm24_read(addr, buf, size);
return res == TRUE ? size : 0;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
if (size == 0)
{
return 0;
}
uint32_t addr = eeprom_fm24.addr + offset;
BOOL res = eeprom_fm24_write(addr, (uint8_t *)buf, size);
return res == TRUE ? (int)size : -1;
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-01-26 armink the first version
*/
#include "eeprom_m95.h"
#include <fal.h>
static int init(void);
static int erase(long offset, size_t size);
static int read1(long offset, uint8_t *buf, size_t size);
static int read2(long offset, uint8_t *buf, size_t size);
static int write1(long offset, const uint8_t *buf, size_t size);
static int write2(long offset, const uint8_t *buf, size_t size);
// 1.定义 flash 设备
struct fal_flash_dev eeprom_m95_1 =
{
.name = EEPROM_M95_1_DEV_NAME,
.addr = 10 * M95_PAGE_SIZE_256,
.len = EEPROM_M95_1_SIZE - 10 * M95_PAGE_SIZE_256,
.blk_size = EEPROM_M95_1_BLOCK_SIZE,
.ops = {init, read1, write1, erase},
.write_gran = 1}; // 设置写粒度,单位 bitEPPROM写粒度为1bit
struct fal_flash_dev eeprom_m95_2 =
{
.name = EEPROM_M95_2_DEV_NAME,
.addr = 0x000000,
.len = EEPROM_M95_2_SIZE,
.blk_size = EEPROM_M95_2_BLOCK_SIZE,
.ops = {init, read2, write2, erase},
.write_gran = 1};
static int init(void)
{
return 1;
}
static int erase(long offset, size_t size)
{
// uint8_t erase_size = size > FAL_ERASE_SIZE ? FAL_ERASE_SIZE : size;
// uint8_t buf[FAL_ERASE_SIZE];
// osel_memset(buf, 0xFF, FAL_ERASE_SIZE);
// for (uint8_t i = 0; i < (size / M95_PAGE_SIZE_256); i++)
// {
// uint32_t addr = eeprom_m95_1.addr + offset + i * M95_PAGE_SIZE_256;
// eeprom_m95_write(M95_1, addr, (uint8_t *)buf, erase_size);
// }
return size;
}
static int read1(long offset, uint8_t *buf, size_t size)
{
/* You can add your code under here. */
uint32_t addr = eeprom_m95_1.addr + offset;
BOOL res = eeprom_m95_read(M95_1, addr, buf, size);
return res == TRUE ? size : 0;
}
static int write1(long offset, const uint8_t *buf, size_t size)
{
uint32_t addr = eeprom_m95_1.addr + offset;
BOOL res = eeprom_m95_write(M95_1, addr, (uint8_t *)buf, size);
return res == TRUE ? (int)size : -1;
}
static int read2(long offset, uint8_t *buf, size_t size)
{
/* You can add your code under here. */
uint32_t addr = eeprom_m95_2.addr + offset;
BOOL res = eeprom_m95_read(M95_2, addr, buf, size);
return res == TRUE ? size : 0;
}
static int write2(long offset, const uint8_t *buf, size_t size)
{
uint32_t addr = eeprom_m95_2.addr + offset;
BOOL res = eeprom_m95_write(M95_2, addr, (uint8_t *)buf, size);
return res == TRUE ? (int)size : -1;
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Initialize interface.
*
* Some initialize interface for this library.
*/
#include <flashdb.h>
#include <fdb_low_lvl.h>
#include <string.h>
#include <inttypes.h>
#ifdef FDB_USING_FILE_POSIX_MODE
#if !defined(_MSC_VER)
#include <unistd.h>
#endif
#endif /* FDB_USING_FILE_POSIX_MODE */
#define FDB_LOG_TAG ""
#if !defined(FDB_USING_FAL_MODE) && !defined(FDB_USING_FILE_MODE)
#error "Please defined the FDB_USING_FAL_MODE or FDB_USING_FILE_MODE macro"
#endif
fdb_err_t _fdb_init_ex(fdb_db_t db, const char *name, const char *path, fdb_db_type type, void *user_data)
{
FDB_ASSERT(db);
FDB_ASSERT(name);
FDB_ASSERT(path);
if (db->init_ok) {
return FDB_NO_ERR;
}
db->name = name;
db->type = type;
db->user_data = user_data;
if (db->file_mode) {
#ifdef FDB_USING_FILE_MODE
memset(db->cur_file_sec, FDB_FAILED_ADDR, FDB_FILE_CACHE_TABLE_SIZE * sizeof(db->cur_file_sec[0]));
/* must set when using file mode */
FDB_ASSERT(db->sec_size != 0);
FDB_ASSERT(db->max_size != 0);
#ifdef FDB_USING_FILE_POSIX_MODE
memset(db->cur_file, -1, FDB_FILE_CACHE_TABLE_SIZE * sizeof(db->cur_file[0]));
#else
memset(db->cur_file, 0, FDB_FILE_CACHE_TABLE_SIZE * sizeof(db->cur_file[0]));
#endif
db->storage.dir = path;
FDB_ASSERT(strlen(path) != 0)
#endif
} else {
#ifdef FDB_USING_FAL_MODE
size_t block_size;
/* FAL (Flash Abstraction Layer) initialization */
fal_init();
/* check the flash partition */
if ((db->storage.part = fal_partition_find(path)) == NULL) {
FDB_INFO("Error: Partition (%s) not found.\n", path);
return FDB_PART_NOT_FOUND;
}
block_size = fal_flash_device_find(db->storage.part->flash_name)->blk_size;
if (db->sec_size == 0) {
db->sec_size = block_size;
} else {
/* must be aligned with block size */
if (db->sec_size % block_size != 0) {
FDB_INFO("Error: db sector size (%" PRIu32 ") MUST align with block size (%zu).\n", db->sec_size, block_size);
return FDB_INIT_FAILED;
}
}
db->max_size = db->storage.part->len;
#endif /* FDB_USING_FAL_MODE */
}
/* the block size MUST to be the Nth power of 2 */
FDB_ASSERT((db->sec_size & (db->sec_size - 1)) == 0);
/* must align with sector size */
if (db->max_size % db->sec_size != 0) {
FDB_INFO("Error: db total size (%" PRIu32 ") MUST align with sector size (%" PRIu32 ").\n", db->max_size, db->sec_size);
return FDB_INIT_FAILED;
}
/* must has more than or equal 2 sectors */
if (db->max_size / db->sec_size < 2) {
FDB_INFO("Error: db MUST has more than or equal 2 sectors, current has %" PRIu32 " sector(s)\n", db->max_size / db->sec_size);
return FDB_INIT_FAILED;
}
return FDB_NO_ERR;
}
void _fdb_init_finish(fdb_db_t db, fdb_err_t result)
{
static bool log_is_show = false;
if (result == FDB_NO_ERR) {
db->init_ok = true;
if (!log_is_show) {
FDB_INFO("FlashDB V%s is initialize success.\n", FDB_SW_VERSION);
FDB_INFO("You can get the latest version on https://github.com/armink/FlashDB .\n");
log_is_show = true;
}
} else if (!db->not_formatable) {
FDB_INFO("Error: %s (%s@%s) is initialize fail (%d).\n", db->type == FDB_DB_TYPE_KV ? "KVDB" : "TSDB",
db->name, _fdb_db_path(db), (int)result);
}
}
void _fdb_deinit(fdb_db_t db)
{
FDB_ASSERT(db);
if (db->init_ok) {
#ifdef FDB_USING_FILE_MODE
for (int i = 0; i < FDB_FILE_CACHE_TABLE_SIZE; i++) {
#ifdef FDB_USING_FILE_POSIX_MODE
if (db->cur_file[i] > 0) {
close(db->cur_file[i]);
}
#else
if (db->cur_file[i] != 0) {
fclose(db->cur_file[i]);
}
#endif /* FDB_USING_FILE_POSIX_MODE */
}
#endif /* FDB_USING_FILE_MODE */
}
db->init_ok = false;
}
const char *_fdb_db_path(fdb_db_t db)
{
if (db->file_mode) {
#ifdef FDB_USING_FILE_MODE
return db->storage.dir;
#else
return NULL;
#endif
}
else {
#ifdef FDB_USING_FAL_MODE
return db->storage.part->name;
#else
return NULL;
#endif
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief configuration file
*/
#ifndef _FDB_CFG_H_
#define _FDB_CFG_H_
/* using KVDB feature */
#define FDB_USING_KVDB
#ifdef FDB_USING_KVDB
/* Auto update KV to latest default when current KVDB version number is changed. @see fdb_kvdb.ver_num */
#define FDB_KV_AUTO_UPDATE
#endif
/* using TSDB (Time series database) feature */
#define FDB_USING_TSDB
/* Using FAL storage mode */
#define FDB_USING_FAL_MODE
#ifdef FDB_USING_FAL_MODE
/* the flash write granularity, unit: bit
* only support 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1)/ 64(stm32f7)/ 128(stm32h5) */
#define FDB_WRITE_GRAN 1 /* @note you must define it for a value */
#endif
/* Using file storage mode by LIBC file API, like fopen/fread/fwrte/fclose */
/* #define FDB_USING_FILE_LIBC_MODE */
/* Using file storage mode by POSIX file API, like open/read/write/close */
/* #define FDB_USING_FILE_POSIX_MODE */
/* MCU Endian Configuration, default is Little Endian Order. */
/* #define FDB_BIG_ENDIAN */
/* log print macro. default EF_PRINT macro is printf() */
/* #define FDB_PRINT(...) my_printf(__VA_ARGS__) */
/* print debug information */
// #define FDB_DEBUG_ENABLE
#endif /* _FDB_CFG_H_ */

View File

@ -0,0 +1,385 @@
/*
* Copyright (c) 2020-2023, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Public definition.
*/
#ifndef _FDB_DEF_H_
#define _FDB_DEF_H_
#ifdef FDB_USING_NATIVE_ASSERT
#include <assert.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/* software version number */
#define FDB_SW_VERSION "2.1.1"
#define FDB_SW_VERSION_NUM 0x20101
/* the KV max name length must less then it */
#ifndef FDB_KV_NAME_MAX
#define FDB_KV_NAME_MAX 64
#endif
/* the KV cache table size, it will improve KV search speed when using cache */
#ifndef FDB_KV_CACHE_TABLE_SIZE
#define FDB_KV_CACHE_TABLE_SIZE 64
#endif
/* the sector cache table size, it will improve KV save speed when using cache */
#ifndef FDB_SECTOR_CACHE_TABLE_SIZE
#define FDB_SECTOR_CACHE_TABLE_SIZE 8
#endif
#if (FDB_KV_CACHE_TABLE_SIZE > 0) && (FDB_SECTOR_CACHE_TABLE_SIZE > 0)
#define FDB_KV_USING_CACHE
#endif
#if defined(FDB_USING_FILE_LIBC_MODE) || defined(FDB_USING_FILE_POSIX_MODE)
#define FDB_USING_FILE_MODE
#endif
/* the file cache table size, it will improve GC speed in file mode when using cache */
#ifndef FDB_FILE_CACHE_TABLE_SIZE
#define FDB_FILE_CACHE_TABLE_SIZE 4
#endif
#ifndef FDB_WRITE_GRAN
#define FDB_WRITE_GRAN 1
#endif
/* log function. default FDB_PRINT macro is printf() */
// #ifndef FDB_PRINT
// #define FDB_PRINT(...) printf(__VA_ARGS__)
// #endif
#ifndef FDB_PRINT
#define FDB_PRINT(...)
#endif
#define FDB_LOG_PREFIX1() FDB_PRINT("[FlashDB]" FDB_LOG_TAG)
#define FDB_LOG_PREFIX2() FDB_PRINT(" ")
#define FDB_LOG_PREFIX() \
FDB_LOG_PREFIX1(); \
FDB_LOG_PREFIX2()
#ifdef FDB_DEBUG_ENABLE
#define FDB_DEBUG(...) \
FDB_LOG_PREFIX(); \
FDB_PRINT("(%s:%d) ", __FILE__, __LINE__); \
FDB_PRINT(__VA_ARGS__)
#else
#define FDB_DEBUG(...)
#endif
/* routine print function. Must be implement by user. */
#define FDB_INFO(...) \
FDB_LOG_PREFIX(); \
FDB_PRINT(__VA_ARGS__)
/* assert for developer. */
#ifdef FDB_USING_NATIVE_ASSERT
#define FDB_ASSERT(EXPR) assert(EXPR);
#else
#ifndef FDB_ASSERT
#define FDB_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
FDB_INFO("(%s) has assert failed at %s.\n", #EXPR, __func__); \
while (1) \
; \
}
#endif /* FDB_ASSERT */
#endif /* FDB_USING_NATIVE_ASSERT */
#define FDB_KVDB_CTRL_SET_SEC_SIZE 0x00 /**< set sector size control command, this change MUST before database initialization */
#define FDB_KVDB_CTRL_GET_SEC_SIZE 0x01 /**< get sector size control command */
#define FDB_KVDB_CTRL_SET_LOCK 0x02 /**< set lock function control command */
#define FDB_KVDB_CTRL_SET_UNLOCK 0x03 /**< set unlock function control command */
#define FDB_KVDB_CTRL_SET_FILE_MODE 0x09 /**< set file mode control command, this change MUST before database initialization */
#define FDB_KVDB_CTRL_SET_MAX_SIZE 0x0A /**< set database max size in file mode control command, this change MUST before database initialization */
#define FDB_KVDB_CTRL_SET_NOT_FORMAT 0x0B /**< set database NOT format mode control command, this change MUST before database initialization */
#define FDB_TSDB_CTRL_SET_SEC_SIZE 0x00 /**< set sector size control command, this change MUST before database initialization */
#define FDB_TSDB_CTRL_GET_SEC_SIZE 0x01 /**< get sector size control command */
#define FDB_TSDB_CTRL_SET_LOCK 0x02 /**< set lock function control command */
#define FDB_TSDB_CTRL_SET_UNLOCK 0x03 /**< set unlock function control command */
#define FDB_TSDB_CTRL_SET_ROLLOVER 0x04 /**< set rollover control command, this change MUST after database initialization */
#define FDB_TSDB_CTRL_GET_ROLLOVER 0x05 /**< get rollover control command */
#define FDB_TSDB_CTRL_GET_LAST_TIME 0x06 /**< get last save time control command */
#define FDB_TSDB_CTRL_SET_FILE_MODE 0x09 /**< set file mode control command, this change MUST before database initialization */
#define FDB_TSDB_CTRL_SET_MAX_SIZE 0x0A /**< set database max size in file mode control command, this change MUST before database initialization */
#define FDB_TSDB_CTRL_SET_NOT_FORMAT 0x0B /**< set database NOT formatable mode control command, this change MUST before database initialization */
#ifdef FDB_USING_TIMESTAMP_64BIT
typedef int64_t fdb_time_t;
#else
typedef int32_t fdb_time_t;
#endif /* FDB_USING_TIMESTAMP_64BIT */
typedef fdb_time_t (*fdb_get_time)(void);
struct fdb_default_kv_node
{
char *key;
void *value;
size_t value_len;
};
struct fdb_default_kv
{
struct fdb_default_kv_node *kvs;
size_t num;
};
/* error code */
typedef enum
{
FDB_NO_ERR,
FDB_ERASE_ERR,
FDB_READ_ERR,
FDB_WRITE_ERR,
FDB_PART_NOT_FOUND,
FDB_KV_NAME_ERR,
FDB_KV_NAME_EXIST,
FDB_SAVED_FULL,
FDB_INIT_FAILED,
} fdb_err_t;
enum fdb_kv_status
{
FDB_KV_UNUSED,
FDB_KV_PRE_WRITE,
FDB_KV_WRITE,
FDB_KV_PRE_DELETE,
FDB_KV_DELETED,
FDB_KV_ERR_HDR,
#define FDB_KV_STATUS_NUM 6
};
typedef enum fdb_kv_status fdb_kv_status_t;
enum fdb_tsl_status
{
FDB_TSL_UNUSED,
FDB_TSL_PRE_WRITE,
FDB_TSL_WRITE,
FDB_TSL_USER_STATUS1,
FDB_TSL_DELETED,
FDB_TSL_USER_STATUS2,
#define FDB_TSL_STATUS_NUM 6
};
typedef enum fdb_tsl_status fdb_tsl_status_t;
/* key-value node object */
struct fdb_kv
{
fdb_kv_status_t status; /**< node status, @see fdb_kv_status_t */
bool crc_is_ok; /**< node CRC32 check is OK */
uint8_t name_len; /**< name length */
uint32_t magic; /**< magic word(`K`, `V`, `4`, `0`) */
uint32_t len; /**< node total length (header + name + value), must align by FDB_WRITE_GRAN */
uint32_t value_len; /**< value length */
char name[FDB_KV_NAME_MAX]; /**< name */
struct
{
uint32_t start; /**< node start address */
uint32_t value; /**< value start address */
} addr;
};
typedef struct fdb_kv *fdb_kv_t;
struct fdb_kv_iterator
{
struct fdb_kv curr_kv; /**< Current KV we get from the iterator */
uint32_t iterated_cnt; /**< How many KVs have we iterated already */
size_t iterated_obj_bytes; /**< Total storage size of KVs we have iterated. */
size_t iterated_value_bytes; /**< Total value size of KVs we have iterated. */
uint32_t sector_addr; /**< Current sector address we're iterating. DO NOT touch it. */
uint32_t traversed_len; /**< Traversed sector total length. */
};
typedef struct fdb_kv_iterator *fdb_kv_iterator_t;
/* time series log node object */
struct fdb_tsl
{
fdb_tsl_status_t status; /**< node status, @see fdb_log_status_t */
fdb_time_t time; /**< node timestamp */
uint32_t log_len; /**< log length, must align by FDB_WRITE_GRAN */
struct
{
uint32_t index; /**< node index address */
uint32_t log; /**< log data address */
} addr;
};
typedef struct fdb_tsl *fdb_tsl_t;
typedef bool (*fdb_tsl_cb)(fdb_tsl_t tsl, void *arg);
typedef enum
{
FDB_DB_TYPE_KV,
FDB_DB_TYPE_TS,
} fdb_db_type;
/* the flash sector store status */
enum fdb_sector_store_status
{
FDB_SECTOR_STORE_UNUSED,
FDB_SECTOR_STORE_EMPTY,
FDB_SECTOR_STORE_USING,
FDB_SECTOR_STORE_FULL,
#define FDB_SECTOR_STORE_STATUS_NUM 4
};
typedef enum fdb_sector_store_status fdb_sector_store_status_t;
/* the flash sector dirty status */
enum fdb_sector_dirty_status
{
FDB_SECTOR_DIRTY_UNUSED,
FDB_SECTOR_DIRTY_FALSE,
FDB_SECTOR_DIRTY_TRUE,
FDB_SECTOR_DIRTY_GC,
#define FDB_SECTOR_DIRTY_STATUS_NUM 4
};
typedef enum fdb_sector_dirty_status fdb_sector_dirty_status_t;
/* KVDB section information */
struct kvdb_sec_info
{
bool check_ok; /**< sector header check is OK */
struct
{
fdb_sector_store_status_t store; /**< sector store status @see fdb_sector_store_status_t */
fdb_sector_dirty_status_t dirty; /**< sector dirty status @see sector_dirty_status_t */
} status;
uint32_t addr; /**< sector start address */
uint32_t magic; /**< magic word(`E`, `F`, `4`, `0`) */
uint32_t combined; /**< the combined next sector number, 0xFFFFFFFF: not combined */
size_t remain; /**< remain size */
uint32_t empty_kv; /**< the next empty KV node start address */
};
typedef struct kvdb_sec_info *kv_sec_info_t;
/* TSDB section information */
struct tsdb_sec_info
{
bool check_ok; /**< sector header check is OK */
fdb_sector_store_status_t status; /**< sector store status @see fdb_sector_store_status_t */
uint32_t addr; /**< sector start address */
uint32_t magic; /**< magic word(`T`, `S`, `L`, `0`) */
fdb_time_t start_time; /**< the first start node's timestamp, 0xFFFFFFFF: unused */
fdb_time_t end_time; /**< the last end node's timestamp, 0xFFFFFFFF: unused */
uint32_t end_idx; /**< the last end node's index, 0xFFFFFFFF: unused */
fdb_tsl_status_t end_info_stat[2]; /**< the last end node's info status */
size_t remain; /**< remain size */
uint32_t empty_idx; /**< the next empty node index address */
uint32_t empty_data; /**< the next empty node's data end address */
};
typedef struct tsdb_sec_info *tsdb_sec_info_t;
struct kv_cache_node
{
uint16_t name_crc; /**< KV name's CRC32 low 16bit value */
uint16_t active; /**< KV node access active degree */
uint32_t addr; /**< KV node address */
};
typedef struct kv_cache_node *kv_cache_node_t;
/* database structure */
typedef struct fdb_db *fdb_db_t;
struct fdb_db
{
const char *name; /**< database name */
fdb_db_type type; /**< database type */
union
{
#ifdef FDB_USING_FAL_MODE
const struct fal_partition *part; /**< flash partition for saving database */
#endif
#ifdef FDB_USING_FILE_MODE
const char *dir; /**< directory path for saving database */
#endif
} storage;
uint32_t sec_size; /**< flash section size. It's a multiple of block size */
uint32_t max_size; /**< database max size. It's a multiple of section size */
uint32_t oldest_addr; /**< the oldest sector start address */
bool init_ok; /**< initialized successfully */
bool file_mode; /**< is file mode, default is false */
bool not_formatable; /**< is can NOT be formated mode, default is false */
#ifdef FDB_USING_FILE_MODE
uint32_t cur_file_sec[FDB_FILE_CACHE_TABLE_SIZE]; /**< last operate sector address */
#if defined(FDB_USING_FILE_POSIX_MODE)
int cur_file[FDB_FILE_CACHE_TABLE_SIZE]; /**< current file object */
#elif defined(FDB_USING_FILE_LIBC_MODE)
FILE *cur_file[FDB_FILE_CACHE_TABLE_SIZE]; /**< current file object */
#endif /* FDB_USING_FILE_MODE */
uint32_t cur_sec; /**< current operate sector address */
#endif
void (*lock)(fdb_db_t db); /**< lock the database operate */
void (*unlock)(fdb_db_t db); /**< unlock the database operate */
void *user_data;
};
/* KVDB structure */
struct fdb_kvdb
{
struct fdb_db parent; /**< inherit from fdb_db */
struct fdb_default_kv default_kvs; /**< default KV */
bool gc_request; /**< request a GC check */
bool in_recovery_check; /**< is in recovery check status when first reboot */
struct fdb_kv cur_kv;
struct kvdb_sec_info cur_sector;
bool last_is_complete_del;
#ifdef FDB_KV_USING_CACHE
/* KV cache table */
struct kv_cache_node kv_cache_table[FDB_KV_CACHE_TABLE_SIZE];
/* sector cache table, it caching the sector info which status is current using */
struct kvdb_sec_info sector_cache_table[FDB_SECTOR_CACHE_TABLE_SIZE];
#endif /* FDB_KV_USING_CACHE */
#ifdef FDB_KV_AUTO_UPDATE
uint32_t ver_num; /**< setting version number for update */
#endif
void *user_data;
};
typedef struct fdb_kvdb *fdb_kvdb_t;
/* TSDB structure */
struct fdb_tsdb
{
struct fdb_db parent; /**< inherit from fdb_db */
struct tsdb_sec_info cur_sec; /**< current using sector */
fdb_time_t last_time; /**< last TSL timestamp */
fdb_get_time get_time; /**< the current timestamp get function */
size_t max_len; /**< the maximum length of each log */
bool rollover; /**< the oldest data will rollover by newest data, default is true */
void *user_data;
};
typedef struct fdb_tsdb *fdb_tsdb_t;
/* blob structure */
struct fdb_blob
{
void *buf; /**< blob data buffer */
size_t size; /**< blob data buffer size */
struct
{
uint32_t meta_addr; /**< saved KV or TSL index address */
uint32_t addr; /**< blob data saved address */
size_t len; /**< blob data saved length */
} saved;
};
typedef struct fdb_blob *fdb_blob_t;
#ifdef __cplusplus
}
#endif
#endif /* _FDB_DEF_H_ */

View File

@ -0,0 +1,318 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Copyright (c) 2020, enkiller, <462747508@qq.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <flashdb.h>
#include <fdb_low_lvl.h>
#define FDB_LOG_TAG "[file]"
#ifdef FDB_USING_FILE_MODE
#define DB_PATH_MAX 256
static void get_db_file_path(fdb_db_t db, uint32_t addr, char *path, size_t size)
{
#define DB_NAME_MAX 8
/* from db_name.fdb.0 to db_name.fdb.n */
char file_name[DB_NAME_MAX + 4 + 10];
uint32_t sec_addr = FDB_ALIGN_DOWN(addr, db->sec_size);
int index = sec_addr / db->sec_size;
snprintf(file_name, sizeof(file_name), "%.*s.fdb.%d", DB_NAME_MAX, db->name, index);
if (strlen(db->storage.dir) + 1 + strlen(file_name) >= size) {
/* path is too long */
FDB_INFO("Error: db (%s) file path (%s) is too log.\n", file_name, db->storage.dir);
FDB_ASSERT(0)
}
snprintf(path, size, "%s/%s", db->storage.dir, file_name);
}
#if defined(FDB_USING_FILE_POSIX_MODE)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if !defined(_MSC_VER)
#include <unistd.h>
#endif
static int get_file_from_cache(fdb_db_t db, uint32_t sec_addr)
{
for (int i = 0; i < FDB_FILE_CACHE_TABLE_SIZE; i++) {
if (db->cur_file_sec[i] == sec_addr)
return db->cur_file[i];
}
return -1;
}
static void update_file_cache(fdb_db_t db, uint32_t sec_addr, int fd)
{
int free_index = FDB_FILE_CACHE_TABLE_SIZE;
for (int i = 0; i < FDB_FILE_CACHE_TABLE_SIZE; i++) {
if (db->cur_file_sec[i] == sec_addr) {
db->cur_file[i] = fd;
return;
} else if (db->cur_file[i] == -1) {
free_index = i;
}
}
if (fd > 0) {
if (free_index < FDB_FILE_CACHE_TABLE_SIZE) {
db->cur_file[free_index] = fd;
db->cur_file_sec[free_index] = sec_addr;
} else {
/* cache is full, move to end */
for (int i = FDB_FILE_CACHE_TABLE_SIZE - 1; i > 0; i--) {
close(db->cur_file[i]);
memcpy(&db->cur_file[i], &db->cur_file[i - 1], sizeof(db->cur_file[0]));
memcpy(&db->cur_file_sec[i], &db->cur_file_sec[i - 1], sizeof(db->cur_file_sec[0]));
}
/* add to head */
db->cur_file[0] = fd;
db->cur_file_sec[0] = sec_addr;
}
}
}
static int open_db_file(fdb_db_t db, uint32_t addr, bool clean)
{
uint32_t sec_addr = FDB_ALIGN_DOWN(addr, db->sec_size);
int fd = get_file_from_cache(db, sec_addr);
char path[DB_PATH_MAX];
if (fd <= 0 || clean) {
get_db_file_path(db, addr, path, DB_PATH_MAX);
if (fd > 0) {
close(fd);
fd = -1;
update_file_cache(db, sec_addr, fd);
}
if (clean) {
/* clean the old file */
int clean_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0777);
if (clean_fd <= 0) {
FDB_INFO("Error: open (%s) file failed.\n", path);
}
else {
close(clean_fd);
clean_fd = -1;
}
}
if (get_file_from_cache(db, sec_addr) < 0) {
/* open the database file */
fd = open(path, O_RDWR, 0777);
update_file_cache(db, sec_addr, fd);
}
db->cur_sec = sec_addr;
}
return fd;
}
fdb_err_t _fdb_file_read(fdb_db_t db, uint32_t addr, void *buf, size_t size)
{
fdb_err_t result = FDB_NO_ERR;
int fd = open_db_file(db, addr, false);
if (fd > 0) {
/* get the offset address is relative to the start of the current file */
addr = addr % db->sec_size;
if ((lseek(fd, addr, SEEK_SET) != (int32_t)addr) || (read(fd, buf, size) != (ssize_t)size))
result = FDB_READ_ERR;
} else {
result = FDB_READ_ERR;
}
return result;
}
fdb_err_t _fdb_file_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync)
{
fdb_err_t result = FDB_NO_ERR;
int fd = open_db_file(db, addr, false);
if (fd > 0) {
/* get the offset address is relative to the start of the current file */
addr = addr % db->sec_size;
if ((lseek(fd, addr, SEEK_SET) != (int32_t)addr) || (write(fd, buf, size) != (ssize_t)size))
result = FDB_WRITE_ERR;
if(sync) {
fsync(fd);
}
} else {
result = FDB_WRITE_ERR;
}
return result;
}
fdb_err_t _fdb_file_erase(fdb_db_t db, uint32_t addr, size_t size)
{
fdb_err_t result = FDB_NO_ERR;
int fd = open_db_file(db, addr, true);
if (fd > 0) {
#define BUF_SIZE 32
uint8_t buf[BUF_SIZE];
size_t i;
lseek(fd, 0, SEEK_SET);
for (i = 0; i * BUF_SIZE < size; i++)
{
memset(buf, 0xFF, BUF_SIZE);
write(fd, buf, BUF_SIZE);
}
memset(buf, 0xFF, BUF_SIZE);
write(fd, buf, size - i * BUF_SIZE);
fsync(fd);
} else {
result = FDB_ERASE_ERR;
}
return result;
}
#elif defined(FDB_USING_FILE_LIBC_MODE)
static FILE *get_file_from_cache(fdb_db_t db, uint32_t sec_addr)
{
for (int i = 0; i < FDB_FILE_CACHE_TABLE_SIZE; i++) {
if (db->cur_file_sec[i] == sec_addr)
return db->cur_file[i];
}
return NULL;
}
static void update_file_cache(fdb_db_t db, uint32_t sec_addr, FILE *fd)
{
int free_index = FDB_FILE_CACHE_TABLE_SIZE;
for (int i = 0; i < FDB_FILE_CACHE_TABLE_SIZE; i++) {
if (db->cur_file_sec[i] == sec_addr) {
db->cur_file[i] = fd;
return;
}
else if (db->cur_file[i] == 0) {
free_index = i;
}
}
if (fd) {
if (free_index < FDB_FILE_CACHE_TABLE_SIZE) {
db->cur_file[free_index] = fd;
db->cur_file_sec[free_index] = sec_addr;
}
else {
/* cache is full, move to end */
for (int i = FDB_FILE_CACHE_TABLE_SIZE - 1; i > 0; i--) {
fclose(db->cur_file[i]);
memcpy(&db->cur_file[i], &db->cur_file[i - 1], sizeof(db->cur_file[0]));
memcpy(&db->cur_file_sec[i], &db->cur_file_sec[i - 1], sizeof(db->cur_file_sec[0]));
}
/* add to head */
db->cur_file[0] = fd;
db->cur_file_sec[0] = sec_addr;
}
}
}
static FILE *open_db_file(fdb_db_t db, uint32_t addr, bool clean)
{
uint32_t sec_addr = FDB_ALIGN_DOWN(addr, db->sec_size);
FILE *fd = get_file_from_cache(db, sec_addr);
char path[DB_PATH_MAX];
if (fd == NULL || clean) {
get_db_file_path(db, addr, path, DB_PATH_MAX);
if (fd) {
fclose(fd);
fd = NULL;
update_file_cache(db, sec_addr, fd);
}
if (clean) {
/* clean the old file */
FILE *clean_fd = fopen(path, "wb+");
if (clean_fd == NULL) {
FDB_INFO("Error: open (%s) file failed.\n", path);
} else {
fclose(clean_fd);
clean_fd = NULL;
}
}
if (get_file_from_cache(db, sec_addr) == NULL) {
/* open the database file */
fd = fopen(path, "rb+");
update_file_cache(db, sec_addr, fd);
}
db->cur_sec = sec_addr;
}
return fd;
}
fdb_err_t _fdb_file_read(fdb_db_t db, uint32_t addr, void *buf, size_t size)
{
fdb_err_t result = FDB_NO_ERR;
FILE *fp = open_db_file(db, addr, false);
if (fp) {
addr = addr % db->sec_size;
if ((fseek(fp, addr, SEEK_SET) != 0) || (fread(buf, size, 1, fp) != size))
result = FDB_READ_ERR;
} else {
result = FDB_READ_ERR;
}
return result;
}
fdb_err_t _fdb_file_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync)
{
fdb_err_t result = FDB_NO_ERR;
FILE *fp = open_db_file(db, addr, false);
if (fp) {
addr = addr % db->sec_size;
if ((fseek(fp, addr, SEEK_SET) != 0) || (fwrite(buf, size, 1, fp) != size))
result = FDB_READ_ERR;
if(sync) {
fflush(fp);
}
} else {
result = FDB_READ_ERR;
}
return result;
}
fdb_err_t _fdb_file_erase(fdb_db_t db, uint32_t addr, size_t size)
{
fdb_err_t result = FDB_NO_ERR;
FILE *fp = open_db_file(db, addr, true);
if (fp != NULL) {
#define BUF_SIZE 32
uint8_t buf[BUF_SIZE];
size_t i;
fseek(fp, 0, SEEK_SET);
for (i = 0; i * BUF_SIZE < size; i++)
{
memset(buf, 0xFF, BUF_SIZE);
fwrite(buf, BUF_SIZE, 1, fp);
}
memset(buf, 0xFF, BUF_SIZE);
fwrite(buf, size - i * BUF_SIZE, 1, fp);
fflush(fp);
} else {
result = FDB_ERASE_ERR;
}
return result;
}
#endif /* defined(FDB_USING_FILE_LIBC_MODE) */
#endif /* FDB_USING_FILE_MODE */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief low level API and definition
*/
#ifndef _FDB_LOW_LVL_H_
#define _FDB_LOW_LVL_H_
#include <fdb_cfg.h>
#include <fdb_def.h>
#if (FDB_WRITE_GRAN == 1)
#define FDB_STATUS_TABLE_SIZE(status_number) ((status_number * FDB_WRITE_GRAN + 7)/8)
#else
#define FDB_STATUS_TABLE_SIZE(status_number) (((status_number - 1) * FDB_WRITE_GRAN + 7)/8)
#endif
/* the data is erased */
#define FDB_BYTE_ERASED 0xFF
/* the data is written */
#define FDB_BYTE_WRITTEN 0x00
/* Return the most contiguous size aligned at specified width. RT_ALIGN(13, 4)
* would return 16.
*/
#define FDB_ALIGN(size, align) (((size) + (align) - 1) - (((size) + (align) -1) % (align)))
/* align by write granularity */
#define FDB_WG_ALIGN(size) (FDB_ALIGN(size, ((FDB_WRITE_GRAN + 7)/8)))
/**
* Return the down number of aligned at specified width. RT_ALIGN_DOWN(13, 4)
* would return 12.
*/
#define FDB_ALIGN_DOWN(size, align) (((size) / (align)) * (align))
/* align down by write granularity */
#define FDB_WG_ALIGN_DOWN(size) (FDB_ALIGN_DOWN(size, (FDB_WRITE_GRAN + 7)/8))
#define FDB_STORE_STATUS_TABLE_SIZE FDB_STATUS_TABLE_SIZE(FDB_SECTOR_STORE_STATUS_NUM)
#define FDB_DIRTY_STATUS_TABLE_SIZE FDB_STATUS_TABLE_SIZE(FDB_SECTOR_DIRTY_STATUS_NUM)
/* the data is unused */
#if (FDB_BYTE_ERASED == 0xFF)
#define FDB_DATA_UNUSED 0xFFFFFFFF
#else
#define FDB_DATA_UNUSED 0x00000000
#endif
/* invalid address */
#define FDB_FAILED_ADDR 0xFFFFFFFF
size_t _fdb_set_status(uint8_t status_table[], size_t status_num, size_t status_index);
size_t _fdb_get_status(uint8_t status_table[], size_t status_num);
uint32_t _fdb_continue_ff_addr(fdb_db_t db, uint32_t start, uint32_t end);
fdb_err_t _fdb_init_ex(fdb_db_t db, const char *name, const char *part_name, fdb_db_type type, void *user_data);
void _fdb_init_finish(fdb_db_t db, fdb_err_t result);
void _fdb_deinit(fdb_db_t db);
const char *_fdb_db_path(fdb_db_t db);
fdb_err_t _fdb_write_status(fdb_db_t db, uint32_t addr, uint8_t status_table[], size_t status_num, size_t status_index, bool sync);
size_t _fdb_read_status(fdb_db_t db, uint32_t addr, uint8_t status_table[], size_t total_num);
fdb_err_t _fdb_flash_read(fdb_db_t db, uint32_t addr, void *buf, size_t size);
fdb_err_t _fdb_flash_erase(fdb_db_t db, uint32_t addr, size_t size);
fdb_err_t _fdb_flash_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync);
#endif /* _FDB_LOW_LVL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,320 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief utils
*
* Some utils for this library.
*/
#include <stdio.h>
#include <string.h>
#include <flashdb.h>
#include <fdb_low_lvl.h>
#define FDB_LOG_TAG "[utils]"
static const uint32_t crc32_table[] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/**
* Calculate the CRC32 value of a memory buffer.
*
* @param crc accumulated CRC32 value, must be 0 on first call
* @param buf buffer to calculate CRC32 value for
* @param size bytes in buffer
*
* @return calculated CRC32 value
*/
uint32_t fdb_calc_crc32(uint32_t crc, const void *buf, size_t size)
{
const uint8_t *p;
p = (const uint8_t *)buf;
crc = crc ^ ~0U;
while (size--) {
crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
}
return crc ^ ~0U;
}
size_t _fdb_set_status(uint8_t status_table[], size_t status_num, size_t status_index)
{
size_t byte_index = SIZE_MAX;
/*
* | write garn | status0 | status1 | status2 | status3 |
* ------------------------------------------------------------------------------------------------------
* | 1bit | 0xFF | 0x7F | 0x3F | 0x1F
* ------------------------------------------------------------------------------------------------------
* | 8bit | 0xFF FF FF | 0x00 FF FF | 0x00 00 FF | 0x00 00 00
* ------------------------------------------------------------------------------------------------------
* | 32bit | 0xFFFFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF | 0x00FFFFFF 00FFFFFF | 0x00FFFFFF 00FFFFFF
* | | 0xFFFFFFFF | 0xFFFFFFFF | 0xFFFFFFFF | 0x00FFFFFF
* ------------------------------------------------------------------------------------------------------
* | | 0xFFFFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF
* | 64bit | 0xFFFFFFFF FFFFFFFF | 0xFFFFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF
* | | 0xFFFFFFFF FFFFFFFF | 0xFFFFFFFF FFFFFFFF | 0xFFFFFFFF FFFFFFFF | 0x00FFFFFF FFFFFFFF
*/
memset(status_table, FDB_BYTE_ERASED, FDB_STATUS_TABLE_SIZE(status_num));
if (status_index > 0) {
#if (FDB_WRITE_GRAN == 1)
byte_index = (status_index - 1) / 8;
#if (FDB_BYTE_ERASED == 0xFF)
status_table[byte_index] &= (0x00ff >> (status_index % 8));
#else
status_table[byte_index] |= (0x00ff >> (status_index % 8));
#endif
#else
byte_index = (status_index - 1) * (FDB_WRITE_GRAN / 8);
status_table[byte_index] = FDB_BYTE_WRITTEN;
#endif /* FDB_WRITE_GRAN == 1 */
}
return byte_index;
}
size_t _fdb_get_status(uint8_t status_table[], size_t status_num)
{
size_t i = 0, status_num_bak = --status_num;
while (status_num --) {
/* get the first 0 position from end address to start address */
#if (FDB_WRITE_GRAN == 1)
if ((status_table[status_num / 8] & (0x80 >> (status_num % 8))) == 0x00) {
break;
}
#else /* (FDB_WRITE_GRAN == 8) || (FDB_WRITE_GRAN == 32) || (FDB_WRITE_GRAN == 64) */
if (status_table[status_num * FDB_WRITE_GRAN / 8] == FDB_BYTE_WRITTEN) {
break;
}
#endif /* FDB_WRITE_GRAN == 1 */
i++;
}
return status_num_bak - i;
}
fdb_err_t _fdb_write_status(fdb_db_t db, uint32_t addr, uint8_t status_table[], size_t status_num, size_t status_index, bool sync)
{
fdb_err_t result = FDB_NO_ERR;
size_t byte_index;
FDB_ASSERT(status_index < status_num);
FDB_ASSERT(status_table);
/* set the status first */
byte_index = _fdb_set_status(status_table, status_num, status_index);
/* the first status table value is all 1, so no need to write flash */
if (byte_index == SIZE_MAX) {
return FDB_NO_ERR;
}
#if (FDB_WRITE_GRAN == 1)
result = _fdb_flash_write(db, addr + byte_index, (uint32_t *)&status_table[byte_index], 1, sync);
#else /* (FDB_WRITE_GRAN == 8) || (FDB_WRITE_GRAN == 32) || (FDB_WRITE_GRAN == 64) */
/* write the status by write granularity
* some flash (like stm32 onchip) NOT supported repeated write before erase */
result = _fdb_flash_write(db, addr + byte_index, (uint32_t *) &status_table[byte_index], FDB_WRITE_GRAN / 8, sync);
#endif /* FDB_WRITE_GRAN == 1 */
return result;
}
size_t _fdb_read_status(fdb_db_t db, uint32_t addr, uint8_t status_table[], size_t total_num)
{
FDB_ASSERT(status_table);
_fdb_flash_read(db, addr, (uint32_t *) status_table, FDB_STATUS_TABLE_SIZE(total_num));
return _fdb_get_status(status_table, total_num);
}
/*
* find the continue 0xFF flash address to end address
*/
uint32_t _fdb_continue_ff_addr(fdb_db_t db, uint32_t start, uint32_t end)
{
uint8_t buf[32], last_data = FDB_BYTE_WRITTEN;
size_t i, addr = start, read_size;
for (; start < end; start += sizeof(buf)) {
if (start + sizeof(buf) < end) {
read_size = sizeof(buf);
} else {
read_size = end - start;
}
_fdb_flash_read(db, start, (uint32_t *) buf, read_size);
for (i = 0; i < read_size; i++) {
if (last_data != FDB_BYTE_ERASED && buf[i] == FDB_BYTE_ERASED) {
addr = start + i;
}
last_data = buf[i];
}
}
if (last_data == FDB_BYTE_ERASED) {
return FDB_WG_ALIGN(addr);
} else {
return end;
}
}
/**
* Make a blob object.
*
* @param blob blob object
* @param value_buf value buffer
* @param buf_len buffer length
*
* @return new blob object
*/
fdb_blob_t fdb_blob_make(fdb_blob_t blob, const void *value_buf, size_t buf_len)
{
blob->buf = (void *)value_buf;
blob->size = buf_len;
return blob;
}
/**
* Read the blob object in database.
*
* @param db database object
* @param blob blob object
*
* @return read length
*/
size_t fdb_blob_read(fdb_db_t db, fdb_blob_t blob)
{
size_t read_len = blob->size;
if (read_len > blob->saved.len) {
read_len = blob->saved.len;
}
if (_fdb_flash_read(db, blob->saved.addr, blob->buf, read_len) != FDB_NO_ERR) {
read_len = 0;
}
return read_len;
}
#ifdef FDB_USING_FILE_MODE
extern fdb_err_t _fdb_file_read(fdb_db_t db, uint32_t addr, void *buf, size_t size);
extern fdb_err_t _fdb_file_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync);
extern fdb_err_t _fdb_file_erase(fdb_db_t db, uint32_t addr, size_t size);
#endif /* FDB_USING_FILE_LIBC */
fdb_err_t _fdb_flash_read(fdb_db_t db, uint32_t addr, void *buf, size_t size)
{
fdb_err_t result = FDB_NO_ERR;
if (db->file_mode) {
#ifdef FDB_USING_FILE_MODE
return _fdb_file_read(db, addr, buf, size);
#else
return FDB_READ_ERR;
#endif
} else {
#ifdef FDB_USING_FAL_MODE
if (fal_partition_read(db->storage.part, addr, (uint8_t *) buf, size) < 0) {
result = FDB_READ_ERR;
}
#endif
}
return result;
}
fdb_err_t _fdb_flash_erase(fdb_db_t db, uint32_t addr, size_t size)
{
fdb_err_t result = FDB_NO_ERR;
if (db->file_mode) {
#ifdef FDB_USING_FILE_MODE
return _fdb_file_erase(db, addr, size);
#else
return FDB_ERASE_ERR;
#endif /* FDB_USING_FILE_MODE */
} else {
#ifdef FDB_USING_FAL_MODE
if (fal_partition_erase(db->storage.part, addr, size) < 0) {
result = FDB_ERASE_ERR;
}
#endif
}
return result;
}
fdb_err_t _fdb_flash_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync)
{
fdb_err_t result = FDB_NO_ERR;
if (db->file_mode) {
#ifdef FDB_USING_FILE_MODE
return _fdb_file_write(db, addr, buf, size, sync);
#else
return FDB_WRITE_ERR;
#endif /* FDB_USING_FILE_MODE */
} else {
#ifdef FDB_USING_FAL_MODE
if (fal_partition_write(db->storage.part, addr, (uint8_t *)buf, size) < 0)
{
result = FDB_WRITE_ERR;
}
#endif
}
return result;
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Public APIs.
*/
#ifndef _FLASHDB_H_
#define _FLASHDB_H_
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
#include <fdb_cfg.h>
#ifdef FDB_USING_FAL_MODE
#include <fal.h>
#endif
#include <fdb_def.h>
#ifdef __cplusplus
extern "C" {
#endif
/* FlashDB database API */
fdb_err_t fdb_kvdb_init (fdb_kvdb_t db, const char *name, const char *path, struct fdb_default_kv *default_kv,
void *user_data);
void fdb_kvdb_control(fdb_kvdb_t db, int cmd, void *arg);
fdb_err_t fdb_kvdb_check(fdb_kvdb_t db);
fdb_err_t fdb_kvdb_deinit(fdb_kvdb_t db);
fdb_err_t fdb_tsdb_init (fdb_tsdb_t db, const char *name, const char *path, fdb_get_time get_time, size_t max_len,
void *user_data);
void fdb_tsdb_control(fdb_tsdb_t db, int cmd, void *arg);
fdb_err_t fdb_tsdb_deinit(fdb_tsdb_t db);
/* blob API */
fdb_blob_t fdb_blob_make (fdb_blob_t blob, const void *value_buf, size_t buf_len);
size_t fdb_blob_read (fdb_db_t db, fdb_blob_t blob);
/* Key-Value API like a KV DB */
fdb_err_t fdb_kv_set (fdb_kvdb_t db, const char *key, const char *value);
char *fdb_kv_get (fdb_kvdb_t db, const char *key);
fdb_err_t fdb_kv_set_blob (fdb_kvdb_t db, const char *key, fdb_blob_t blob);
size_t fdb_kv_get_blob (fdb_kvdb_t db, const char *key, fdb_blob_t blob);
fdb_err_t fdb_kv_del (fdb_kvdb_t db, const char *key);
fdb_kv_t fdb_kv_get_obj (fdb_kvdb_t db, const char *key, fdb_kv_t kv);
fdb_blob_t fdb_kv_to_blob (fdb_kv_t kv, fdb_blob_t blob);
fdb_err_t fdb_kv_set_default (fdb_kvdb_t db);
void fdb_kv_print (fdb_kvdb_t db);
fdb_kv_iterator_t fdb_kv_iterator_init(fdb_kvdb_t db, fdb_kv_iterator_t itr);
bool fdb_kv_iterate (fdb_kvdb_t db, fdb_kv_iterator_t itr);
/* Time series log API like a TSDB */
fdb_err_t fdb_tsl_append (fdb_tsdb_t db, fdb_blob_t blob);
fdb_err_t fdb_tsl_append_with_ts(fdb_tsdb_t db, fdb_blob_t blob, fdb_time_t timestamp);
void fdb_tsl_iter (fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg);
void fdb_tsl_iter_reverse(fdb_tsdb_t db, fdb_tsl_cb cb, void *cb_arg);
void fdb_tsl_iter_by_time(fdb_tsdb_t db, fdb_time_t from, fdb_time_t to, fdb_tsl_cb cb, void *cb_arg);
size_t fdb_tsl_query_count (fdb_tsdb_t db, fdb_time_t from, fdb_time_t to, fdb_tsl_status_t status);
fdb_err_t fdb_tsl_set_status (fdb_tsdb_t db, fdb_tsl_t tsl, fdb_tsl_status_t status);
void fdb_tsl_clean (fdb_tsdb_t db);
fdb_blob_t fdb_tsl_to_blob (fdb_tsl_t tsl, fdb_blob_t blob);
/* fdb_utils.c */
uint32_t fdb_calc_crc32(uint32_t crc, const void *buf, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* _FLASHDB_H_ */

View File

@ -0,0 +1,38 @@
# 移植说明
## 简介
[FlashDB](http://armink.gitee.io/flashdb/#/zh-cn/) 是一款超轻量级的嵌入式数据库专注于提供嵌入式产品的数据存储方案。FlashDB 不仅支持传统的基于文件系统的数据库模式,而且结合了 Flash 的特性,具有较强的性能及可靠性。并在保证极低的资源占用前提下,尽可能延长 Flash 使用寿命。
## 使用场景
如今物联网产品种类越来越多运行时产生的数据种类及总量及也在不断变大。FlashDB 提供了多样化的数据存储方案,不仅资源占用小,并且存储容量大,非常适合用于物联网产品。下面是主要应用场景:
* **键值数据库**
* 产品参数存储
* 用户配置信息存储
* 小文件管理
* **时序数据库**
* 存储动态产生的结构化数据:如 温湿度传感器采集的环境监测信息,智能手环实时记录的人体健康信息等
* 记录运行日志:存储产品历史的运行日志,异常告警的记录等
本项目使用3块EPPROM
## 文件移植
项目地址 https://github.com/armink/FlashDB
引入目录中的文件
.\FlashDB\src
.\FlashDB\inc
.\FlashDB\port\fal\src
.\FlashDB\port\fal\inc
> fal_cfg.h 这个文件为用户自定义升级的时候不要覆盖

Some files were not shown because too many files have changed in this diff Show More