keil开发环境配置

1.CCS开发学习链接
2.keil+sysconfig开发

CCS常用方法

多文件编译

如何在CCS中添加文件路径

11
11

keil+Syconfig开发出现常见问题及其解决方法

1.在导入SDK中Syconfig文件时候没用Import选项:说明版本太低需要更新Kei版本
2.出现错误:Missing argument: —board or —device must be specified解决方法
参考链接: Missing argument: —board or —device must be specified解决方法
1

确保在该文件显示在屏幕上时,再打开SysConfig

CCS基础及其TI

GPIO

1
2
3
4
5
6

DL_GPIO_setPins(GPIO_Regs *gpio, uint32_t pins)//设置为输出高电平

DL_GPIO_ClearPins(GPIO_Regs *gpio, uint32_t pins)//设置为输出低电平

DL_GPIO_togglePins(GPIO_Regs *gpio, uint32_t pins)//高低电平翻转

系统时钟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// SysTick->VAL,滴答定时器去延迟
void delay_ms(uint32_t ms)
{
uint32_t ticks = ms * (CPUCLK_FREQ / 1000); // 1000 * (32000000 / 1000) = 32,000,000
uint32_t count_new = 0, count_old = 0;
uint32_t count = 0;
count_old = SysTick->VAL;

while(1)
{
// 获取最新的计数值
count_new = SysTick->VAL;

// 如果最新和上一次的值不一样,说明有改动
if (count_new != count_old)
{
// 如果新的值比旧的值小
if (count_new < count_old)
{
count = count + (count_old - count_new);
}
// 如果新的值比旧的值大
else if (count_new > count_old)
}
{
count = count + SysTick->LOAD - count_new + count_old;

// 更新旧的值
count_old = count_new;

// 如果已经达到我们的计数的次数了就结束
if (count >= ticks) return;
}
}
}

2.
volatile uint32_t delay_value = 0;

void delay_ms(uint32_t ms)
{
delay_value = 1000;
while (delay_value != 0);
}

void SysTick_Handler(void)
{
delay_value--;
}

SY配置
SY配置

阻塞延迟和非阻塞延迟:

采用空语句的方式,称为阻塞延迟
采用中断的方式,称为非阻塞延迟

邓兄给的代码:
邓哥给的代码

串口通信

1
2
3
4
5
6
7
8
9
10
11
12
13

//两个串口发送函数
DL_UART_transmitData(UART_0_INST,'c' )//1.串口种类2.发送字符
//发送字符串函数
void uart_sendString(char* str)
{
while(*str!=0)
{
while(DL_UART_isBusy(UART_0_INST)==true);
DL_UART_transmitData(UART_0_INST, *str);
str++;
}
}

PWM输出

SY设置:
SY设置

1
2

DL_TimerG_setCaptureCompareValue(PWM_INST, 500, DL_TIMER_CC_0_INDEX);//用于设置PWM占空比输出

常用模块

OLED屏幕

MPU6050

MPU6050设置

刚刚移MPU库,移半天一堆错,想想还是自己积分算角度吧
学习链接: !基于江科大MPU6050移植进入MSPM0

基于江科大MPU6050姿态解算代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "stm32f10x.h"
#include "MPU6050.h"
#include "math.h"

#define RtA (57.2957795f) // 弧度转角度,180/π ≈ 57.2957795
#define Ki 0.005f // 积分系数
#define DT 0.005f // 计算周期的一半,单位s

// 加速度和角速度
int16_t AX, AY, AZ, GX, GY, GZ;

typedef struct {
float c1, c2, c3, a1, a2, a3, a;
} Degree;

Degree d;

typedef struct {
float q0, q1, q2, q3;
float exInt, eyInt, ezInt;
} Quater;

Quater q = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};

void Dmp_Init(void) {
MPU6050_Init();
}

void MPU6050_Read(void) {
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);

// 转换为物理量
d.c1 = GX / 131.0f; // 角速度(°/s)
d.c2 = GY / 131.0f;
d.c3 = GZ / 131.0f;

// 转换为rad/s
d.c1 /= RtA;
d.c2 /= RtA;
d.c3 /= RtA;

d.a1 = AX / 16384.0f; // 加速度(g)
d.a2 = AY / 16384.0f;
d.a3 = AZ / 16384.0f;

// 加速度归一化
float norm = sqrtf(d.a1 * d.a1 + d.a2 * d.a2 + d.a3 * d.a3);
if (norm > 1e-6f) { // 防止除零
float inv_norm = 1.0f / norm;
d.a1 *= inv_norm;
d.a2 *= inv_norm;
d.a3 *= inv_norm;
d.a = 1.0f;
} else {
d.a = 0.0f;
}
}

void ComputeEulerAngles(float *pitch, float *roll, float *yaw) {
MPU6050_Read();

// 计算姿态误差
float gx = d.c1, gy = d.c2, gz = d.c3;
float gravity_x = 2.0f * (q.q1 * q.q3 - q.q0 * q.q2);
float gravity_y = 2.0f * (q.q0 * q.q1 + q.q2 * q.q3);
float gravity_z = q.q0*q.q0 - q.q1 * q.q1 - q.q2 * q.q2 + q.q3*q.q3;

float error_x = d.a2 * gravity_z - d.a3 * gravity_y;
float error_y = d.a3 * gravity_x - d.a1 * gravity_z;
float error_z = d.a1 * gravity_y - d.a2 * gravity_x;

// 更新四元数
float Kp = 0.5f;

// 误差积分
q.exInt += Ki * error_x ;
q.eyInt += Ki * error_y ;
q.ezInt += Ki * error_z ;

// 修正角速度
gx += Kp * error_x + q.exInt;
gy += Kp * error_y + q.eyInt;
gz += Kp * error_z + q.ezInt;

// 四元数微分方程
float q0_dot = (-q.q1 * gx - q.q2 * gy - q.q3 * gz) * DT;
float q1_dot = (q.q0 * gx - q.q3 * gy + q.q2 * gz) * DT;
float q2_dot = (q.q3 * gx + q.q0 * gy - q.q1 * gz) * DT;
float q3_dot = (-q.q2 * gx + q.q1 * gy + q.q0 * gz) * DT;

// 更新四元数
q.q0 += q0_dot;
q.q1 += q1_dot;
q.q2 += q2_dot;
q.q3 += q3_dot;

// 归一化
float norm = sqrtf(q.q0 * q.q0 + q.q1 * q.q1 + q.q2 * q.q2 + q.q3 * q.q3);
if (norm > 1e-6f) {
float inv_norm = 1.0f / norm;
q.q0 *= inv_norm;
q.q1 *= inv_norm;
q.q2 *= inv_norm;
q.q3 *= inv_norm;
}

// 计算欧拉角
float q0q0 = q.q0 * q.q0;
float q1q1 = q.q1 * q.q1;
float q2q2 = q.q2 * q.q2;
float q3q3 = q.q3 * q.q3;

*roll = atan2f(2.0f * (q.q2 * q.q3 + q.q0 * q.q1), q0q0 - q1q1 - q2q2 + q3q3);
*pitch = asinf(-2.0f * (q.q1 * q.q3 - q.q0 * q.q2));
*yaw = atan2f(2.0f * (q.q1 * q.q2 + q.q0 * q.q3), q0q0 + q1q1 - q2q2 - q3q3);

// // 转换为度
// *roll *= RtA;
// *pitch *= RtA;
// *yaw *= RtA;
}

真题

24年颠赛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <math.h>          // 包含数学库,用于计算正弦波等
#include <stdint.h> // 包含标准整数类型库,确保跨平台兼容

// 假设硬件接口函数(需根据实际硬件实现)
void step_motor_x(int steps, int dir); // 控制X轴步进电机移动,steps为步数,dir为方向(1正,0反)
void step_motor_y(int steps, int dir); // 控制Y轴步进电机移动,steps为步数,dir为方向(1正,0反)
int read_encoder_x(void); // 读取X轴编码器位置,返回当前步数
int read_encoder_y(void); // 读取Y轴编码器位置,返回当前步数
void delay_us(uint32_t us); // 微秒延时函数,用于控制脉冲间隔

// 步进电机参数
#define STEPS_PER_MM 100 // 每毫米对应的步数,根据电机和驱动器设置
#define MAX_SPEED 1000 // 最大速度(步/秒),限制电机运行速度
#define ACCELERATION 2000 // 加速度(步/秒²),用于梯形加减速计算

// PID 参数
#define KP 0.5 // 比例增益,控制位置误差的响应强度
#define KI 0.01 // 积分增益,消除稳态误差
#define KD 0.1 // 微分增益,抑制位置超调
#define DT 0.001 // PID控制周期(秒),与硬件定时器匹配

// PID 控制结构体
typedef struct { // 定义PID控制器结构体
float kp, ki, kd; // PID参数:比例、积分、微分增益
float integral; // 积分项,累积误差以消除稳态误差
float last_error; // 上一次误差,用于计算微分项
float max_output; // 输出限制,防止速度过高(步/秒)
} PIDController; // 结构体类型名为PIDController

// 初始化 PID 控制器
void pid_init(PIDController *pid) { // 函数:初始化PID控制器
pid->kp = KP; // 设置比例增益为定义的KP值
pid->ki = KI; // 设置积分增益为定义的KI值
pid->kd = KD; // 设置微分增益为定义的KD值
pid->integral = 0; // 初始化积分项为0
pid->last_error = 0; // 初始化上一次误差为0
pid->max_output = MAX_SPEED; // 设置最大输出速度为MAX_SPEED
}

// PID 计算
float pid_compute(PIDController *pid, int target_pos, int actual_pos) { // 函数:计算PID输出
float error = target_pos - actual_pos; // 计算当前位置误差(目标位置 - 实际位置)
pid->integral += error * DT; // 更新积分项:累积误差乘以控制周期
float derivative = (error - pid->last_error) / DT; // 计算微分项:误差变化率
float output = pid->kp * error + pid->ki * pid->integral + pid->kd * derivative; // 计算PID输出:P + I + D
if (output > pid->max_output) output = pid->max_output; // 限制输出不超过最大速度
if (output < -pid->max_output) output = -pid->max_output; // 限制输出不低于负最大速度
pid->last_error = error; // 更新上一次误差
return output; // 返回计算出的速度(步/秒)
}

// PID 控制移动
void pid_move(int target_steps, int dir, int axis) { // 函数:使用PID控制电机移动
PIDController pid; // 定义PID控制器实例
pid_init(&pid); // 初始化PID控制器
int current_pos = (axis == 0) ? read_encoder_x() : read_encoder_y(); // 读取当前轴(X或Y)的编码器位置
int step_count = 0; // 初始化步数计数器
int total_steps = abs(target_steps); // 计算总步数(取绝对值)

while (step_count < total_steps) { // 循环直到完成所有步数
current_pos = (axis == 0) ? read_encoder_x() : read_encoder_y(); // 读取当前实际位置
float speed = pid_compute(&pid, step_count, current_pos); // 通过PID计算当前速度
if (axis == 0) step_motor_x(1, dir); // 如果是X轴,移动一步
else step_motor_y(1, dir); // 如果是Y轴,移动一步
delay_us(1000000 / (int)fabs(speed)); // 根据速度计算延时(微秒)
step_count++; // 步数计数器加1
}
}

// 直线插补(Bresenham算法,结合 PID)
void draw_line(int x0, int y0, int x1, int y1) { // 函数:绘制直线
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; // 计算X方向差值和符号
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1; // 计算Y方向差值和符号
int err = (dx > dy ? dx : -dy) / 2, e2; // 初始化Bresenham误差项

while (1) { // 循环直到到达终点
pid_move(1, x0 < x1 ? 1 : 0, 0); // X轴移动一步,使用PID控制
pid_move(1, y0 < y1 ? 1 : 0, 1); // Y轴移动一步,使用PID控制
if (x0 == x1 && y0 == y1) break; // 如果到达终点,退出循环
e2 = err; // 保存当前误差
if (e2 > -dx) { err -= dy; x0 += sx; } // 如果误差满足条件,更新X坐标
if (e2 < dy) { err += dx; y0 += sy; } // 如果误差满足条件,更新Y坐标
}
}

// 圆弧插补(中点圆算法,结合 PID)
void draw_circle(int xc, int yc, int r) { // 函数:绘制圆形
int x = 0, y = r; // 初始化圆的起点坐标(x=0, y=半径)
int d = 3 - 2 * r; // 初始化中点圆算法的决策参数
while (x <= y) { // 循环直到x大于y(完成1/8圆弧)
pid_move(1, (xc + x) < xc ? 0 : 1, 0); // 绘制点(xc+x, yc+y)
pid_move(1, (yc + y) < yc ? 0 : 1, 1);
pid_move(1, (xc - x) < xc ? 0 : 1, 0); // 绘制点(xc-x, yc+y)
pid_move(1, (yc + y) < yc ? 0 : 1, 1);
pid_move(1, (xc + x) < xc ? 0 : 1, 0); // 绘制点(xc+x, yc-y)
pid_move(1, (yc - y) < yc ? 0 : 1, 1);
pid_move(1, (xc - x) < xc ? 0 : 1, 0); // 绘制点(xc-x, yc-y)
pid_move(1, (yc - y) < yc ? 0 : 1, 1);
pid_move(1, (xc + y) < xc ? 0 : 1, 0); // 绘制点(xc+y, yc+x)
pid_move(1, (yc + x) < yc ? 0 : 1, 1);
pid_move(1, (xc - y) < xc ? 0 : 1, 0); // 绘制点(xc-y, yc+x)
pid_move(1, (yc + x) < yc ? 0 : 1, 1);
pid_move(1, (xc + y) < xc ? 0 : 1, 0); // 绘制点(xc+y, yc-x)
pid_move(1, (yc - x) < yc ? 0 : 1, 1);
pid_move(1, (xc - y) < xc ? 0 : 1, 0); // 绘制点(xc-y, yc-x)
pid_move(1, (yc - x) < yc ? 0 : 1, 1);

if (d < 0) { // 如果决策参数小于0,选择内侧点
d += 4 * x + 6; // 更新决策参数
} else { // 如果决策参数大于等于0,选择外侧点
d += 4 * (x - y) + 10; // 更新决策参数
y--; // Y坐标减1
}
x++; // X坐标加1
}
}

// 正弦波生成(结合 PID)
void draw_sine_wave(int x_start, int x_end, int amplitude, int period) { // 函数:绘制正弦波
for (int x = x_start; x <= x_end; x++) { // 遍历X轴从起点到终点
int y = amplitude * sin(2 * M_PI * x / period); // 计算正弦波Y坐标
pid_move(1, x < (x + 1) ? 1 : 0, 0); // X轴移动一步,使用PID控制
pid_move(1, y < 0 ? 0 : 1, 1); // Y轴移动到正弦波点,使用PID控制
}
}

// 绘制三角形
void draw_triangle(int x1, int y1, int x2, int y2, int x3, int y3) { // 函数:绘制三角形
draw_line(x1, y1, x2, y2); // 绘制第一条边
draw_line(x2, y2, x3, y3); // 绘制第二条边
draw_line(x3, y3, x1, y1); // 绘制第三条边
}

// 主函数
int main() { // 程序主入口
// 绘制三角形(坐标单位:毫米,转换为步数)
draw_triangle(0 * STEPS_PER_MM, 0 * STEPS_PER_MM, // 三角形顶点1:(0, 0)
50 * STEPS_PER_MM, 0 * STEPS_PER_MM, // 三角形顶点2:(50, 0)
25 * STEPS_PER_MM, 43 * STEPS_PER_MM); // 三角形顶点3:(25, 43)

// 绘制圆形(中心(50, 50),半径20mm)
draw_circle(50 * STEPS_PER_MM, 50 * STEPS_PER_MM, 20 * STEPS_PER_MM); // 绘制圆形

// 绘制正弦波(x从0到100,幅度10mm,周期50mm)
draw_sine_wave(0 * STEPS_PER_MM, 100 * STEPS_PER_MM, 10 * STEPS_PER_MM, 50 * STEPS_PER_MM); // 绘制正弦波

return 0; // 程序结束
}