C语言在无浮点无数学库MCU上实现int8_t坐标0.2°精度绕原点旋转
无浮点无数学库的MCU坐标旋转实现方案
核心思路
因为要求0.2°的角度增量精度,全程用定点运算+预生成三角函数表实现,完全避免浮点运算和数学库调用,仅使用int32_t作为运算中间类型,符合MCU的资源限制。
前置准备
- 角度量化:把0~360°按0.2°为步长拆分,总共有
360/0.2=1800个步长,任意输入角度先转成对应步长,对1800取模后即可覆盖所有旋转场景 - 预生成定点三角函数表:使用Q15格式(1位符号位+15位小数位)存储sin值,即把
sin(步长*0.2°)乘以32768后四舍五入取整,预生成1800个int16_t类型的数值存入代码常量区,占用Flash仅3.6KB,对MCU资源压力极低。cos值可通过cosθ = sin(θ+90°)的关系直接从sin表取数,无需单独存cos表
运算逻辑
坐标旋转的整数定点版公式如下:
x' = (x * cosθ_q15 - y * sinθ_q15 + 16384) >> 15
y' = (x * sinθ_q15 + y * cosθ_q15 + 16384) >> 15
其中cosθ_q15、sinθ_q15是Q15格式的三角函数值,加16384是做四舍五入,右移15位是还原Q15的缩放比例,得到最终整数坐标。
由于输入x、y是int8_t类型,最大绝对值为128,单步乘法结果最大为128*32767=4194176,远小于int32_t的取值范围,中间运算不会出现溢出。
代码实现示例
#include <stdint.h> // 0.2°为步长,覆盖0~359.8°总共有1800个步长 #define ROT_STEP_COUNT 1800 // Q15格式sin表,预生成规则:sin_table[i] = round(sin(i * 0.2° * π / 180) * 32767) // 以下为示例表片段,完整表可在PC端提前计算后直接填入 static const int16_t sin_table[ROT_STEP_COUNT] = { 0, 114, 228, 343, 457, 571, 686, 800, 914, 1028, // 剩余1790个值省略 32767, 32756, 32745, // 对应90°、89.8°、89.6°... }; // 从sin表获取Q15格式cos值,90°对应步长为450 static int16_t get_cos_q15(int32_t step) { return sin_table[(step + 450) % ROT_STEP_COUNT]; } /** * 坐标绕原点旋转函数 * @param x 输入x坐标,int8_t类型 * @param y 输入y坐标,int8_t类型 * @param angle_deci 输入旋转角度,单位为0.1°,比如40.8°传408,0.2°传2,避免浮点传参 * @param out_x 输出旋转后x坐标 * @param out_y 输出旋转后y坐标 */ void rotate_point(int8_t x, int8_t y, int32_t angle_deci, int8_t *out_x, int8_t *out_y) { // 角度转步长,+1做四舍五入保证0.2°精度 int32_t step = (angle_deci + 1) / 2; // 步长取模到合法范围 step = step % ROT_STEP_COUNT; if (step < 0) step += ROT_STEP_COUNT; int32_t cos_q15 = get_cos_q15(step); int32_t sin_q15 = sin_table[step]; // 用int32_t存中间结果避免溢出 int32_t x_res = (int32_t)x * cos_q15 - (int32_t)y * sin_q15; int32_t y_res = (int32_t)x * sin_q15 + (int32_t)y * cos_q15; // 四舍五入后还原Q15缩放,转成int8_t输出 *out_x = (int8_t)((x_res + 16384) >> 15); *out_y = (int8_t)((y_res + 16384) >> 15); }
验证示例
输入坐标(32, -64),旋转90°,对应angle_deci=900,计算步长为(900+1)/2=450,sin_q15=32767,cos_q15=0:
- x_res = 32*0 - (-64)*32767 = 2097088,(2097088+16384)>>15 = 2113472>>15 = 64
- y_res = 32*32767 + (-64)*0 = 1048544,(1048544+16384)>>15 = 1064928>>15 =32
输出结果为(64,32),和要求完全一致。
资源优化方案
如果MCU Flash空间不足,可仅存储0~90°对应的450个步长的sin表,其余象限的sin、cos值通过符号翻转和索引对称计算得到,仅需900字节Flash即可实现完整功能。
内容的提问来源于stack exchange,提问作者NessDan
相关产品推荐
相关产品推荐

