大三上笔记

目录3

一、    关于STM32库函数运用结构体赋予寄存器地址的方式    2

二、    关于GPIO口上下拉代表的意义    3

三、    Static和extern    3

四、    ARM处理器的工作状态    4

五、    STM32F4中的时钟源    4

六、    Void和void * 的意义    5

七、    链表在newnode后面记得加上newnode->next=NULL    6

八、    *p 和 p 的区别    6

九、    什么是SP指针、PC指针、R1、R2、PSW    6

十、    OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()    6

扫描二维码关注公众号,回复: 5161896 查看本文章

十一、    什么是DOS,什么是BIOS    6

十二、    uC/OS是如何切换任务的    7

十三、    带Hook的钩子函数    7

十四、    uC/OS中任务调用    7

十五、    单片机中一些英文符号的释义    9

十六、    ARM中的指令集    9

十七、    时钟树    10

十八、    关于TI的板子移植程序中各个功能设定在什么文件中    10

十九、    将ucos改成1024个任务需要改写哪些文件    10

二十、    什么是BSP和CSP    10

二十一、    KMP中的next[i]是干什么用的    10

二十二、    BM算法    11

二十三、    ODR和IDR    14

二十四、    BOOT0和BOOT1    14

二十五、    C语言指针和字符串    15

二十六、    DRAM和SRAM    15

二十七、    二维数组\双重指针\数组指针\指针数组的关系    16

二十八、    Short、long、int    17

二十九、    看门狗    17

 

6

  1. 关于STM32库函数运用结构体赋予寄存器地址的方式
    1. 在库函数运用中

      两个全局变量的输入,一个是GPIOA类型的地址,另外一个是初始化配置的枚举定义。初始化的枚举定义是没有地址赋予的,而GPIO是已经在H文件中赋予地址。

    2. 最终变成GPIOA有一个首地址,GPIOA->MODER赋予了一个地址。而后进行的初始化GPIO函数就是用前面定义的初始化结构体先进行赋值然后再送入函数中,在函数中进行地址的查找和对寄存器赋值从而实现了GPIO口的初始化。
  2. 关于GPIO口上下拉代表的意义
    1. 在输出模式下,引脚受ODR寄存器影响。ODR寄存器对应引脚初始化后默认值为0,引脚输出低电平。所以在输出模式下无论上下拉都不会改变引脚输出低电平这个模式。但如果配置上拉能小幅提高电流输出能力。
  3. Staticextern
    1. Static: 它只在定义它的源文件内有效,其他源文件无法访问它。所以一般有这个的还需要在加一步源文件中的封装,然后再在main中调用这个封装。当定义成普通静态变量时,它只能在或者函数中使用不能在其他的函数中调用。静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。
    2. Extern:它其实就相当于引用,是用在这个函数将要放在的这个文件中的,比如main函数要用其他文件的函数,但是这个时候没有include这个函数所在的文件,那么就要在main中加入extern 这个函数,这样就能调用到没有include的函数了,所以加了include就不用extern了。
  4. ARM处理器的工作状态
    1.   ARM的体系结构中,可以工作在三种不同的状态,一是ARM状态,二是Thumb状态及Thumb-2状态,三是调试状态。
    2. ARM状态:处理器工作于32位指令的状态,所有指令均为32位。
    3. Thumb状态:执行16位指令的状态。
    4. 两个状态的切换R0[0] = 0 R0指令将进入ARM状态
    5. Cortex-M3只有thumb-2状态

 

 

 

 

 

  1. STM32F4中的时钟源
    1. HCLK:液晶、内存的相关频率

      PCLK:串口等外部速度较慢的设备频率

      FLCK:内核频率 三者关系是:FLCK = n * (HCLK = n * PCLK)

      AHB分频因子(决定HCLK等于多少),APB2分频因子(决定PCLK2等于的多少),APB1分频因子(决定PCLK1等于多少)

      在我们的F407中HCLK = SYSCLK = PLLCLK = 168MHz

                      PCLK2 = HLCK/2 = 84MHz

                      PCLK1 = HCLK/4 = 42MHz

    2. HSE是高速外部时钟信号,由我们的25MHz无源晶振提供,HIS是高速内部时钟,其频率为16MHz,一般SYSCLK都是HSE或者HIS通过PLL倍频后拿来使用的。
    3. GPIO和USART1和SPI1等高速外设使用的是AHB,所以函数用的是AHB。

      I2C,SPI23和UART2345等用的是APB,所以函数用的hi是APB。

  2. Voidvoid * 的意义
    1. Void是表示对返回类型的限定和函数参数的限定,void a 是错误的
    2. Void *指的是定义一个"不确定类型指针" 这个指针可以接受任意变量的赋值
  3. 链表在newnode后面记得加上newnode->next=NULL
    1. 删除列表头节点指向的指针时要注意头节点指针要指向下下个节点,尤其是在循环列表中
    2. 要搞清楚什么时候是空头节点什么时候是头节点有数据
  4. *p p 的区别
    1. *p 表示 p这个指针指向的变量的值
    2. P 表示p这个指针指向的变量的地址
    3. Int *p = &n; 表示创建一个指针并且把n的地址赋予p及*p指向n;
  5. 什么是SP指针、PC指针、R1R2PSW
    1. CPU 按照 PC 指针,到存储器去取指令代码。
      CPU 按照 SP 指针,到存储器存取地址或数据。
    2. R1\R2就是通用寄存器
    3. PSW就是程序状态寄存器
  6. OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()
    1. OS_ENTER_CRITICAL()是关中断,意思是进入关键临界区,绝不能被中断,OS_EXIT_CRITICAL()是开中断
  7. 什么是DOS,什么是BIOS
    1. BIOS指(Basic Input & Output System,基本输入输出系统 ),相当于一个与硬件直接打交道的原始级操作系统。电脑的架构是这样的:
      硬件——BIOS——操作系统——应用程序,应用程序的指令是通过这几个层次来控制最终的硬件执行。
    2. DOS是英文Disk Operating System的缩写,意思是"磁盘操作系统"。应该指的就是我们用的Win10
  8. uC/OS是如何切换任务的
    1. 我们先来看一下我们自己创建任务的一般结构。如下所示:

      void Task_USER_A(void *pdata) 

      {

            pdata = pdata;

      for(;;){

          //用户代码

          ..............

          //用户代码

         OSTimeDly();      //(1)

         OSTimeDlyHMSM();  //(2)

      }

      }

      在每个已经建立的任务(idel除外)中都会看到(1)或(2)这样的延时函数,(1)/(2)实现任务延时,将当前的任务挂起一段时间,延时函数中会去查询任务就续表中优先级最高的任务,通过调用任务调度OSSched()完成任务切换。挂起当前任务,才能让比当前任务优先级低的任务得到CPU而执行。

  9. Hook的钩子函数
    1.  钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。对每种类型的钩子由系统来维护一个钩子链,最近安装的钩子放在链的开始,而最先安装的钩子放在最后,也就是后加入的先获得控制权。
  10. uC/OS中任务调用
    1. 在延时函数中将当前任务挂起,OSTCBCur中的OSTCBBitX记录的是任务在就绪表数组中的位置,取反然后相与就能在就绪表中去除任务。
    2. 那么延时是怎么实现的呢?

      延时1s,在该函数中计算出ticks = 100,然后赋值给OSTCBCur->OSTCBDly

      ,然后开启中断,在中断大概是10ms进入一次,所以是先延时然后开始寻找下一个任务,而延时中断任务在os_core,c中,延时完要把这个任务重新放到任务就绪表中,以下是函数截图

  11. 单片机中一些英文符号的释义
    1. OSC:振荡器
    2. XTAL:晶振
  12. ARM中的指令集
    1. MSR,MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。
      1. 当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。

      MRS R0,CPSR  @传送CPSR的内容到R0

      1. 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
      2. MSR指令用亍将操作数的内容传送到程序状态寄存器的特定域中。
      3. 该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。
        指令示例:
        MSR CPSR,R0    @传送R0的内容到CPSR
        MSR SPSR,R0    @传送R0的内容到SPSR
        MSR CPSR_c,R0   @传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域
  13. 时钟树
  14. 关于TI的板子移植程序中各个功能设定在什么文件中
    1. 晶振的频率设定在这个文件中
    2. 配置晶振的数组在这个文件中
    3. 获取系统时钟源也在这个文件中
  15. ucos改成1024个任务需要改写哪些文件
  16. 什么是BSPCSP
    1. BSP:板级支持包
    2. CSP:芯片支持包
  17. KMP中的next[i]是干什么用的
    1. 当某一个字符与主串不匹配时,我们应该知道j指针要移动到哪
    2. 最前面的k个字符和j之前的最后k个字符是一样的
    3. 如果用数学公式来表示是这样的

      P[0 ~ k-1] == P[j-k ~ j-1]

      一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

       

      KMP代码实现

       

void makeNext(const char P[],int next[])

{

int q,k;//q:模版字符串下标;k:最大前后缀长度

int m = strlen(P);//模版字符串长度

next[0] = 0;//模版字符串的第一个字符的最大前后缀长度为0

for (q = 1,k = 0; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next

{

while(k > 0 && P[q] != P[k])//递归的求出P[0]···P[q]的最大的相同的前后缀长度k

k = next[k-1]; //不理解没关系看下面的分析,这个while循环是整段代码的精髓所在,确实不好理解

if (P[q] == P[k])//如果相等,那么最大相同前后缀长度加1

{

k++;

}

next[q] = k;

}

}

  1. BM算法

BM字符主要是从右边开始比较,也就是从后面开始,匹配的叫好后缀,遇到不匹配的叫坏字符

  1. 坏字符:

    我们现在将匹配过程中,主串失配位置的字符称之为"坏字符"。根据这个坏字符,我们可以"总结出一些教训",进而改进以上的算法

  1. 坏字符的几种情况:
    1. 坏字符不存在我的模式串中

      这种情况就直接移动到坏字符后面一格就可以了

    2. 坏字符存在我的模式串中

      坏字符存在于还未比对的字符中,那么久把存在的那个坏字符串和模式串中的坏字符对上

每一次不匹配导致的移动都应该是移动到坏字符(如果存在)在模式床中最右端的一个位置

  1. 具体怎么移动到坏字符那里呢?
    1. 首先构造一个hash表,从左到右bc[pattern[i]] = i赋值,因为字符就是256的ACKII码,由于是从左往右遍历,所以在后面的相同字符会覆盖掉前面已经赋值的字符.
    2. 这是只有符合坏字符条件的情况下的代码,可以看出从右到左 应该是不要包含好后缀的而且实际上所谓的hash表不就是坏字符在模式串中的最后面的位数吗.

int bmMatch(const string & text, const string & pat)

{

int *bc = getBc(pat);

//patAt指向了当前pattext对齐的位置

int patAt = 0;

//cmp指向了当前比较的位置

int cmp;

const size_t PATLASTID = pat.length() - 1;

const size_t patLen = pat.length();

const size_t textLen = text.length();

while (patAt + patLen <= textLen)

{

//如果匹配成功,cmp就会来到-1的位置上

//patAt + cmp 指向了text上当前比较的字符

for (cmp = PATLASTID; cmp >= 0 && pat[cmp] == text[patAt + cmp]; --cmp);

 

if (cmp == -1)//找到匹配的信息了 直接退出

break;

else

{

int span = cmp - bc[text[patAt + cmp]];

patAt += (span > 0)? span : 1;

}

}

delete[] bc;

return (patAt + patLen <= textLen)? patAt : -1;

}

  1. 好后缀:

    好后缀就是从右到左匹配的时候,匹配成功的字符,这个字符很有可能也存在于前面未匹配的字符中,如果存在那么就可以直接移动到那边。

    1. 好后缀的几种移动情况:
      1. 首先是前缀中不存在
      2. 其次是前缀中存在一整个好后缀
      3. 最后是前缀中有好后缀的后缀
    2. 建立gs方便移动

int * getGs(const string & pat)

{

const int len = pat.length();

const int lastIndex = len - 1;

int *suffix = suffixes(pat);

int *gs = new int[len];

//找不到对应的子串和前缀

for (int i = 0; i < len; ++i)

gs[i] = len;

//找前缀

for (int i = lastIndex; i >= 0; --i)

{

//存在我们想要的前缀

if (suffix[i] == i + 1)

{

for (int j = 0; j < lastIndex - i; ++j)

{

if (gs[j] == len)

gs[j] = lastIndex - i;

}

}

}

//找中间的匹配子串

for (int i = 0; i < lastIndex; ++i)

{

gs[lastIndex - suffix[i]] = lastIndex - i;

}

delete[] suffix;

return gs;

}

 

  1. ODRIDR

    ODR是配置GPIOx的输出状态寄存器,IDR是配置GPIOx的输入状态寄存器。

  2. BOOT0BOOT1

    BOOT0是不能拿来用的,是复位用的,而BOOT1在启动后就变成了普通io口了可以使用。

  3. C语言指针和字符串
    1. 首先数组对应指针,二维数组就对应双重指针吗?错。二维数组就是二维数组还是一维指针。
    2. 字符串的一些用法:
      1. Strcat:字符串连接,并不返回连接的字符串而是直接把前面一个串变成前+后。strcat_s(PaddC, 1024, P);
      2. Strcpy:字符串赋值strcpy_s(P, PaddC);
      3. Memset:用于字符串清空。memset(str, 0, sizeof(str));
  4. DRAMSRAM

    内存条是dram,而SRAM因为缺点是同容量相比DRAM需要非常多的晶体管发热量也非常大。因此SRAM难以成为大容量的主存储器,通常只用在CPU、GPU中作为缓存,容量也只有几十K至几十M,故采用DRAM。

    Cache存储器:电脑中为高速缓冲存储器,是位于CPU和主存储器DRAM(DynamicRandomAccessMemory)之间,规模较小,但速度很高的存储器,通常由SRAM(StaticRandomAccessMemory静态存储器)组成。它是位于CPU与内存间的一种容量较小但速度很高的存储器。CPU的速度远高于内存,当CPU直接从内存中存取数据时要等待一定时间周期,而Cache则可以保存CPU刚用过或循环使用的一部分数据,如果CPU需要再次使用该部分数据时可从Cache中直接调用,这样就避免了重复存取数据,减少了CPU的等待时间,因而提高了系统的效率。Cache又分为L1Cache(一级缓存)和L2Cache(二级缓存),L1Cache主要是集成在CPU内部,而L2Cache集成在主板上或是CPU上。

  5. 二维数组\双重指针\数组指针\指针数组的关系

首先,二维数组和双重指针表示的是不一样的意思,但是在使用二维数组的形式上都可以表示,但是由于存储空间的形式不同,导致不能相互赋值.

左图为二维数组(数组指针char *c[10];)的形式,右图为双重指针(指针数组char (*c)[10];)的形式.

 

指针是不能指向指针的,只有定义的二级指针才能指向指针.这应该并不是因为指针的原因,应该是语法的关系,否则怎么都是地址,指针不能指向指针的地址.

指针是能指向结构体的

二维数组的定义必须要固定的空间,而二重指针的话就可以动态分配空间给他。这样方便了不定长度的使用,也能更好地利用空间而不用像二维数组那样浪费。

Void指针可以转换为任何类型, 感觉应该是一个开辟最大空间的指针所以能够强制转换成任何指针.

 

如果使用*p来给指针赋值,会改变指针指向的那个内容的值,而p = &I;这样带来的是指针指向内容的改变.

 

 

        

  1. Shortlongint

    百度上说short一般16位,long一般32位,这个和编译器有关,vc就说short最大16,int和long最大32.keil5中 int应该和这个mcu的最大位数一样,short固定16,long感觉应该可以达到64的在64位芯片中。这个方面还没有非常详细地了解。

  2. 看门狗

在程序中一直定时喂狗,然后如果程序跑飞了,就表示一段时间没有喂狗了,看门狗定时器就发送一个信号到reset中重启程序

  1. 人工智能

基本概念:训练集、测试集、特征值、监督学习、非监督学习、半监督学习、分类、回归

概念学习:人类学习概念

猜你喜欢

转载自www.cnblogs.com/bbb-929497723/p/10363975.html