插入排序法是一种稳定排序法,在数据量不大的情况下用起来还是不错的, 比较直观,类似在打扑克的过程中,按照大小来排列手上的扑克牌。但是因为mini-c的原因,标准算法不能直接应用于应广单片机上,我就稍作修改,然后供大家参考。
在mini-c中,数组功能是弱化的,数组下标不能是变量,在新的ide版本中,我不知道数组功能是否已经可以用,我还是按照老办法,用指针实现数组功能。在排序过程中,我还加入了打印功能,方便分析和查看结果。
关于打印功能,我这里要说一下的就是,只是用来方便调试,实际芯片中是没有这个功能的,而且打印功还会影响仿真实时性,所以使用的时候要注意一下。在没有实时性要求,或是一般的数据处理中可以加入这个功能,方便查看结果。
不多说,上代码,一切尽在代码中。。。
#include "extern.h"
/*调试输出开关,关闭之后测试端口不输出了*/
#define DEBUG
/*1m 标记*/
bit msFlag;
/*us计数*/
byte ucUsCnt;
/*ms 计数*/
byte ucMsCnt;
Word Reload_T16;
/*可以用示波器观察对应端口*/
#ifdef DEBUG
bit US100_OUT :pa.7
bit MS_OUT :pa.6
bit MS10_OUT :pa.0
#endif
/**********************************************************************
插入排序法过程,
6 in 5
5,6
5,6 in 3
3,5,6
3,5,6 in 1
1,3,5,6
1,3,5,6 in 8
1,3,5,6,8
1,3,5,6,8 in 7
1,3,5,6,7,8
1,3,5,6,7,8 in 2
1,2,3,5,6,7,8
1,2,3,5,6,7,8 in 4
1,2,3,4,5,6,7,8
**********************************************************************/
byte ucDat[8]={6,5,3, 1, 8,7, 2,4 };//从小到大插入排序
void InserstionSort(void)
{
byte i,j;
byte ucGetDat;
byte ucTmp;
word upDat;
/*从第二个位置开始取数据*/
i=1;
while(i<8)
{
/*取得数据*/
upDat=&ucDat[0]+i;
ucGetDat=*upDat;
/*已经排好队的个数*/
j=i-1;
/*遍历已经排序的所有元素*/
do
{
/*取最后面的一个元素*/
upDat=&ucDat[0]+j;
ucTmp=*upDat;
/*如果该元素大于 新进的元素,那么*/
if(ucGetDat<ucTmp)
{
/*该元素往后挪一个位置*/
upDat+=1;
*upDat=ucTmp;
/*指针指向前一个位置,新进元素插入该元素前面*/
upDat--;
}
else
{
/*新进元素最大,在已经排好序元素的最后面*/
upDat+=1;
/*退出当前比较*/
break;
}
}
while(j--);
/*在已经腾挪好之后地方插入新进元素*/
*upDat=ucGetDat;
#if 1/******调试打印,实际应用中关闭即可************/
.printf("In=%d ",ucGetDat);
ucGetDat=0;
do
{ upDat=&ucDat[0]+ucGetDat;
ucTmp=*upDat;
.printf("sort=%d",ucTmp);
ucGetDat++;
}
while(ucGetDat<=i);
.printf("\n");
#endif
/*数据位置更新*/
i++;
}
}
/*中断服务程序*/
void Interrupt(void)
{
pushaf;
if(Intrq.T16)
{
STT16 Reload_T16;
Intrq.T16 = 0;
ucUsCnt++;
if(ucUsCnt>9)
{
ucUsCnt=0;
/*100us*10=1ms*/
msFlag=1;
}
/*100u task,紧急任务放这边,但这里的任务尽量少,
心脏部位,尽量减少干扰,需要保证tick精准*/
#ifdef DEBUG
if(US100_OUT)
{
US100_OUT=0;
}
else
{
US100_OUT=1;
}
#endif
}
popaf;
}
/*T16设置*/
Void Timer16_Init(void)
{
/*向上计数 1600就发生中断 1600/16M=0.0001s=100us,理论设计*/
//Reload_T16 = 32768 - 1600;
/*根据测算(示波器校准),除去误差(约为20个sysclk周期),设置1580这个值可能更准确,
SYSCLK越快,误差越小.从进入中断开始,到重新设置计数器,中间大概需要20个sysclk周期*/
Reload_T16 = 32768 - 1580;
/*设置计数器值*/
STT16 Reload_T16;
/*配置T16 控制寄存器*/
$ T16M IHRC,/1,BIT15;
INTRQ.T16 = 0;
INTEN.T16 = 1;
msFlag=0;
ucUsCnt=0;
}
void FPPA0 (void)
{
/*注意,修改了sysclk,Reload_T16要做细微调整,可以试着改动sysclk,
会发现Reload_T16误差变大*/
.ADJUST_IC SYSCLK=IHRC/2,IHRC=16MHz,init_ram;
/*开启看门狗*/
CLKMD.En_WatchDog = 1;
wdreset;
/*初始化T16*/
Timer16_Init();
#ifdef DEBUG
$ US100_OUT out,low;
$ MS_OUT out,low;
$ MS10_OUT out,low;
#endif
/*排序之前打印*/
.printf("old=%d,%d,%d,%d,%d,%d,%d,%d\n",ucDat[0],ucDat[1],ucDat[2],ucDat[3],ucDat[4],ucDat[5],ucDat[6],ucDat[7]);
InserstionSort();
/*排序之后打印*/
.printf("new=%d,%d,%d,%d,%d,%d,%d,%d\n",ucDat[0],ucDat[1],ucDat[2],ucDat[3],ucDat[4],ucDat[5],ucDat[6],ucDat[7]);
Engint;
while (1)
{
/*喂狗*/
wdreset;
/*1ms标记*/
if(msFlag)
{
ucMsCnt++;
if(ucMsCnt>9)
{
/*1ms*10=10ms*/
ucMsCnt=0;
/*10mstask 放这里*/
#ifdef DEBUG
if(MS10_OUT)
{
MS10_OUT=0;
}
else
{
MS10_OUT=1;
}
#endif
}
/*1ms task*/
#ifdef DEBUG
if(MS_OUT)
{
MS_OUT=0;
}
else
{
MS_OUT=1;
}
#endif
msFlag=0;
}
}
}
/*creat by zhongvv QQ85547259*/