上电之后main.c 如何在cpu中运行

前言

前面一篇<中断服务子程序是如何被cpu执行的>讲了
1 中断前保护现场,中断后恢复现场。
2 中断向量表的组成和运行过程。
3 堆栈在中断的占用情况。
回顾一下

1 中断前保护现场就是 会保存之前的数据 再进入中断 反之 
中断后 恢复现场就是不保存中断数据 回到原先事件 
2{
 中断向量表的每个表项都会对应 相应的中断源的子程序
 并且直接从R14寄存器取出地址 进行函数执行 pc指针也会存入函数 以便准备下一次的运行。
}
3 {
  在保护现场 堆栈就明显增多 恢复现场明显减少了。
}

复位的概念

************解开复位的神秘面具 其实就一句话 (重要)

复位就是 检查有没有错误的意思 

引起复位的几种原因

上电复位 通道之后的检查有无错误 没有就继续往下上电.
外部手动复位:也就是常见的复位按键 只是换个方式来检查有无出错。和上电复位差不多
区别是 一个是自动 一个是手动 仅此而已。
。。。。。等等的复位。。。。。。。。

中断向量表

这里列出来很多的 中断外部中断对应了不同的优先级  -3是最高的 也就是它会起到一个承上启下的作用 他可以起到手动复位的作用 。并且 cpu 会有一部分单独的特殊中断 称之为异常.上电之后 会先给cpu 检测有无出错现象.没有 就是没有异常在运行.

在这里插入图片描述
在这里插入图片描述
而红箭头指向 没什么都没写 其实他存放的是优先级-2 -1的变量 并且不能被编程 和执行的
并且它是表示 堆栈的 栈顶 根据堆栈的“先进后出”机制 那么它是第一个进去的 也就是最后一个出来的 那么他堆栈空间大小就可以确定了 也就可以说它是一个结束地址。

中断向量表的位置

大概分成两中情况
1 很常规的 源程序 — 中断 函数的 方式 (FLASH不分块 )
在这里插入图片描述

1 他的地址就是 0x0800000 很和常规的没差别。

2 把FLASH分成两块
在这里插入图片描述

相当于 原先的一块 分成了两块 并且他们都有 两个不一样的名字 
名字就是bootlarder和app 
这里可理解为 中断存放的PC指针的地址 就是 bootlarder 或者是 app 
换名字的过程 就是你们所说的重定向 
重定向就是 换一个名字代替而已  和宏定义没区别。

在F103 可以这么实现

NVIC_SetVectorTable(NVIC_VectTab_FLASH, offset);

复位过程

用上面的 第一个例子 讲解  拿到了一个起始地址,也就是栈顶,这就确认了堆栈空间大小 并且存入SP  初始化PC指针 pc指针存放是下一个地址的指令 所以会去执行的是中断复位程序。

在这里插入图片描述
执行完复位程序之后 它会先去检测sysinit函数的复位 如果没有出错
sysinit 作用起效了 他的作用是 初始化RCC 和重定向的初始化 等等。
最后才会执行main (结合下面的图来理解)
在这里插入图片描述

总结

1 上电复位 检查cpu有无异常,有无出错---- 2 确定栈顶位置 也就知道了堆栈空间的大小
 ---3 把存放在R14的地址 取出  返回执行 函数点 因为 pc指针存放下一个地址的指令一直
 运行到了Sysinit 再次复位检查 RCC 和重定向有无出错 没有出错 就初始化 RCC和重定向 ----
 4 最后跳转到main执行 pc指针始终在前面存放。
请多多指教 这位哞
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SPWM(正弦波脉宽调制)是一种常见的交流电变频调速技术,常用于交流电机驱动等领域。在TI DSP上实现SPWM产生程序可以通过以下步骤完成: 1. 初始化IO口和定时器:根据具体的DSP型号和开发板,使用相应的头文件和函数库初始化IO口和定时器。 2. 计算SPWM的占空比:根据所需输出的正弦波频率和振幅,计算每个采样周期的占空比。具体计算方法可以参考SPWM的原理,也可以通过查找相关资料进行了解。 3. 设置定时器自动重载模式:在每个采样周期结束时,使用定时器自动重载模式重新加载占空比值,以实现连续的SPWM波形输出。 4. 运行SPWM产生程序:将SPWM的占空比值写入定时器的比较寄存器,启动定时器,并在每个采样周期结束时更新占空比值,实现连续的SPWM波形输出。 以下是一个简单的C语言SPWM产生程序示例: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #include "DSP2833x_Device.h" #include "DSP2833x_Examples.h" #define PI 3.1415926 #define SAMPLING_FREQ 20000 //采样频率,单位为Hz #define PWM_FREQ 50 //SPWM波形频率,单位为Hz #define PWM_AMPLITUDE 1 //SPWM波形振幅,取值范围为0~1 Uint16 spwm_duty[100]; //SPWM占空比数组 Uint16 spwm_index; //当前SPWM占空比在数组的索引 //计算SPWM占空比值 void calc_spwm_duty(void) { int i; float freq_ratio = PWM_FREQ / (float)SAMPLING_FREQ; //计算频率比值 for(i = 0; i < 100; i++) { spwm_duty[i] = (Uint16)(PWM_AMPLITUDE * sin(2 * PI * freq_ratio * i) * 1000 + 1000); //计算SPWM占空比值 } } void main() { InitSysCtrl(); //初始化系统时钟 InitPieCtrl(); //初始化PIE断 IER = 0x0000; //禁止所有断 IFR = 0x0000; InitPieVectTable(); //初始化PIE断向量表 EALLOW; GpioCtrlRegs.GPAMUX1.all = 0; //将GPIO口设置为普通IO口模式 GpioCtrlRegs.GPADIR.all = 0xFF; //将GPIO口设置为输出模式 EDIS; InitCpuTimers(); //初始化定时器 ConfigCpuTimer(&CpuTimer0, 150, 1000000 / SAMPLING_FREQ); //配置定时器 PieVectTable.TINT0 = &cpu_timer0_isr; //设置定时器断向量 IER |= M_INT1; //使能PIE断 PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //使能定时器断 EINT; //使能全局断 calc_spwm_duty(); //计算SPWM占空比值 spwm_index = 0; //初始化SPWM占空比索引 while(1) { //等待定时器断 } } //定时器断服务函数 interrupt void cpu_timer0_isr(void) { CpuTimer0Regs.TCR.bit.TIF = 1; //清除定时器断标志位 GpioDataRegs.GPASET.all = 0xFF; //设置所有GPIO口为高电平 GpioDataRegs.GPADAT.all = spwm_duty[spwm_index]; //设置当前SPWM占空比值 spwm_index++; //更新SPWM占空比索引 if(spwm_index >= 100) { spwm_index = 0; //超过数组长度时,重置SPWM占空比索引 } } ``` 注意:以上代码仅供参考,在实际应用需要根据具体的DSP型号和开发板进行适当的修改。同时,由于SPWM产生程序需要高精度的定时控制,因此需要注意系统时钟的设置和定时器的溢出时间等参数的配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值