文章基于适用于STM32F4系列,作者使用STM32F401CCU6开发板。
本文章基于此系列和开发板展开讨论。
本系列以SSD1306为主控芯片的I2C接口的0.96寸OLED屏幕为例介绍
内容较多,分节进行
链接
需求分析
指定圆心位置,半径,宽度画出完整的圆
- 确定扫描范围
- 进行扫描
圆的基础知识
在平面内,圆是到定点的距离等于定长的点的集合叫做圆
方程是(x-a)+(y-b)=r
这也就是我们的做选择的基础
确定扫描范围
在图中已经将关键点标出来了
我们只需要在左右顶点之间扫描列,在上下顶点之间扫描页即可
X_Left = X - R - Width - 1;
X_Right = X + R + Width + 1;
Y_Up = (Y - R) / 8 - 1;
Y_Down = (Y + R) / 8 + 1;
这就是计算扫描范围的式子
扫描
这部分只需要扫描整个范围即可,在计算范围时已经包围全部范围进去了
for (int y = Y_Up; y < Y_Down; y++) //扫描页
{
for (int x = X_Left; x < X_Right; x++) //扫描列
{
Circular_Zj = 0;
for (int z = 0; z < 8; z++) //页内的led
{
Circular_Zj >>= 1;
if (Solid == DISABLE) //空心圆
{
if (OLED_Abs(powf(x - X, 2) + powf((y * 8 + z) - Y, 2) - powf(R, 2)) < powf(Width, 2))
{
Circular_Zj |= 0x80;
}
}
else if (Solid == ENABLE) //实心圆
{
if ((powf(x - X, 2) + powf((y * 8 + z) - Y, 2)) < (powf(R, 2) + powf(Width, 2)))
{
Circular_Zj |= 0x80;
}
}
}
OLED_Buffer[y][x] |= Circular_Zj;
}
}
powf
是头文件"arm_math.h"
里的函数,作用是算次方
空心圆判断条件
OLED_Abs(powf(x - X, 2) + powf((y * 8 + z) - Y, 2) - powf(R, 2)) < powf(Width, 2)
因为扫描的时候是平方进行的,因此我们将宽度(Width)平方,避免其数值过大
实心圆
(powf(x - X, 2) + powf((y * 8 + z) - Y, 2)) < (powf(R, 2) + powf(Width, 2))
同样将宽度平方,只需要扫描小于最外边界的即可
函数
c文件(OLED.C)
//画圆 输入横纵坐标,半径和粗细
void OLED_Circular(int X, int Y, int R, int Width, FunctionalState Solid)
{
int X_Left, X_Right, Y_Up, Y_Down;
u8 Circular_Zj;
X_Left = X - R - Width - 1;
X_Right = X + R + Width + 1;
Y_Up = (Y - R) / 8 - 1;
Y_Down = (Y + R) / 8 + 1;
OLED_CandA_LimMaxMin(&X_Left, &X_Right, &Y_Up, &Y_Down);
for (int y = Y_Up; y < Y_Down; y++) //扫描页
{
for (int x = X_Left; x < X_Right; x++) //扫描列
{
Circular_Zj = 0;
for (int z = 0; z < 8; z++) //页内的led
{
Circular_Zj >>= 1;
if (Solid == DISABLE) //空心圆
{
if (OLED_Abs(powf(x - X, 2) + powf((y * 8 + z) - Y, 2) - powf(R, 2)) < powf(Width, 2))
{
Circular_Zj |= 0x80;
}
}
else if (Solid == ENABLE) //实心圆
{
if ((powf(x - X, 2) + powf((y * 8 + z) - Y, 2)) < (powf(R, 2) + powf(Width, 2)))
{
Circular_Zj |= 0x80;
}
}
}
OLED_Buffer[y][x] |= Circular_Zj;
}
}
OLED_Full_Picture(OLED_Buffer);
}
//画圆和圆弧用 限制最大最小值
void OLED_CandA_LimMaxMin(int *X_Left, int *X_Right, int *Y_Up, int *Y_Down)
{
OLED_LimMin(X_Left, 0);
OLED_LimMin(Y_Up, 0);
OLED_LimMax(X_Right, 127);
OLED_LimMax(Y_Down, 63);
}
OLED_LimMin
和OLED_LimMax
在之前文章中给出过了,传送门,作用使输入的数不能超过范围
成品
链接:百度网盘
提取码:ierk