<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>꿈/희망/절망</title>
    <link>https://manggsoft.tistory.com/</link>
    <description>다 안다고 생각하는 순간 모르는게 보이더라...
아는 만큼 보인다..</description>
    <language>ko</language>
    <pubDate>Sun, 2 Aug 2026 07:47:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>얼땅불땅</managingEditor>
    <item>
      <title>타이머/인터럽트</title>
      <link>https://manggsoft.tistory.com/164</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 I2C, SPI, UART, ADC, PWM 글을 하나씩 정리했다. 그런데 PWM을 파다 보니 결국 그 뒤에 있던 건 &lt;b&gt;타이머&lt;/b&gt;였더라. 그래서 이번엔 미뤄뒀던 &lt;b&gt;타이머 / 인터럽트&lt;/b&gt;를 제대로 판다. 사실 이거 두 개는 마이컴의 진짜 기본기라서, 여기까지 오면 기초 시리즈가 한 바퀴 도는 느낌이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;왜 타이머 + 인터럽트인가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LED를 1초마다 깜빡이는 코드를 처음 짤 땐 다들 이렇게 짠다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;while(1)
{
    LED = 1;
    delay_ms(1000);   // 1초 기다림
    LED = 0;
    delay_ms(1000);   // 또 1초 기다림
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작은 한다. 그런데 문제는 저 &lt;code&gt;delay_ms(1000)&lt;/code&gt; 안에서 CPU가 &lt;b&gt;진짜 아무것도 안 하고 멍때린다&lt;/b&gt;는 거다. 1초 동안 그냥 숫자만 세면서 시간을 죽이고 있는 거다. 버튼도 못 읽고, 센서도 못 보고, 통신도 못 한다. LED 하나 깜빡이겠다고 CPU를 통째로 붙잡아두는 셈이다.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;비싼 CPU를 스톱워치로 쓰는 격&lt;/del&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;타이머 + 인터럽트&lt;/b&gt;가 등장한다. 이 둘을 쓰면 CPU는 &lt;b&gt;딴 일을 하면서도&lt;/b&gt; 정확한 타이밍에 LED를 깜빡일 수 있다. 시간 재는 건 타이머(하드웨어)한테 맡기고, 시간 다 되면 인터럽트가 &quot;야, 됐어!&quot; 하고 CPU를 잠깐 불러주는 방식이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;타이머부터 &amp;mdash; 그냥 숫자 세는 기계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타이머(Timer)&lt;/b&gt;는 CPU와 &lt;b&gt;별개로 도는 하드웨어 카운터&lt;/b&gt;다. 하는 일은 단순하다. 클럭 펄스가 하나 들어올 때마다 카운터 값을 &lt;b&gt;1씩 올린다.&lt;/b&gt; 그게 전부다. CPU가 while문 돌리든 말든 상관없이 얘는 자기 페이스로 계속 숫자를 센다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 카운터 값이 담기는 레지스터가 &lt;b&gt;TCNT&lt;/b&gt;(Timer/Counter)다. 예를 들어 &lt;b&gt;8비트 타이머&lt;/b&gt;라면 TCNT는 0부터 시작해서 1, 2, 3&amp;hellip; 이렇게 올라가다가 &lt;b&gt;255&lt;/b&gt;(8비트 최댓값)까지 간다. 그 다음 한 번 더 세면? 담을 자리가 없으니 &lt;b&gt;0으로 뚝 떨어진다.&lt;/b&gt; 이걸 &lt;b&gt;오버플로(overflow)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;TCNT&lt;/b&gt; : 지금 몇까지 셌는지 들어있는 레지스터. 0 &amp;rarr; 255 &amp;rarr; 0 &amp;rarr; 255 &amp;hellip; 반복.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오버플로&lt;/b&gt; : 255에서 한 번 더 세서 0으로 넘칠 때. 이 순간 &quot;이벤트&quot;가 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴페어 매치(compare match)&lt;/b&gt; : 미리 정해둔 비교값과 TCNT가 같아지는 순간. 이것도 이벤트다. (끝까지 안 가고 중간 특정 값에서 알림받고 싶을 때 쓴다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;timer-count.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VMEuL/dJMcagzuE4n/di16xEq88lRtu33mdHxyu1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VMEuL/dJMcagzuE4n/di16xEq88lRtu33mdHxyu1/tfile.svg&quot; data-alt=&quot;TCNT는 0에서 TOP(255)까지 올라갔다가 오버플로로 0으로 뚝 떨어진다. 이 톱니를 무한 반복한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VMEuL/dJMcagzuE4n/di16xEq88lRtu33mdHxyu1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVMEuL%2FdJMcagzuE4n%2Fdi16xEq88lRtu33mdHxyu1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;380&quot; data-filename=&quot;timer-count.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TCNT는 0에서 TOP(255)까지 올라갔다가 오버플로로 0으로 뚝 떨어진다. 이 톱니를 무한 반복한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 자연스럽게 드는 의문. &quot;그럼 8비트 타이머는 255밖에 못 세는데, 1초 같은 긴 시간은 어떻게 재?&quot; 좋은 질문이다. 그래서 두 가지 장치가 있다.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 1.1em; margin: 1.6em 0 0.5em;&quot; data-ke-size=&quot;size23&quot;&gt;① 프리스케일러로 세는 속도를 늦춘다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프리스케일러(prescaler)&lt;/b&gt;는 클럭을 &lt;b&gt;분주(分周)&lt;/b&gt;한다. 쉽게 말해 클럭을 느리게 만들어서 타이머한테 넣어주는 거다. CPU 클럭이 그대로 들어가면 타이머가 너무 빨리 넘쳐서 시간 재기가 힘드니까, 중간에서 &quot;8번에 1번만&quot;, &quot;1024번에 1번만&quot; 이런 식으로 걸러서 천천히 세게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 틱(카운터 1 올라가는) 시간은 이렇게 정해진다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;한 틱 시간 = 프리스케일러 &amp;divide; F_CPU&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 F_CPU가 8MHz이고 프리스케일러가 1024라면, 한 틱 = 1024 &amp;divide; 8,000,000 &amp;asymp; 0.128ms. 이 속도면 8비트 타이머가 0&amp;rarr;255 한 바퀴(256틱) 도는 데 대략 32.8ms 걸린다. 프리스케일러를 키우면 더 느리게, 줄이면 더 빠르게 센다. 세는 속도를 다이얼처럼 조절하는 놈이라고 보면 된다.&lt;/p&gt;
&lt;h3 style=&quot;font-size: 1.1em; margin: 1.6em 0 0.5em;&quot; data-ke-size=&quot;size23&quot;&gt;② 오버플로 횟수를 소프트웨어로 센다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 한 바퀴가 32.8ms면 1초엔 한참 모자란다. 그래서 &lt;b&gt;오버플로가 몇 번 났는지&lt;/b&gt;를 우리가 변수로 센다. 예를 들어 오버플로가 약 30번 쌓이면 대략 1초다. &quot;타이머가 넘칠 때마다 카운트 하나 올리고, 그게 N번 되면 1초 지난 걸로 친다&quot; &amp;mdash; 이 발상이 뒤에 나올 코드의 핵심이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;인터럽트 &amp;mdash; 사건이 나면 하던 일 멈추고 달려가기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &quot;타이머가 오버플로 났다&quot;는 걸 CPU가 어떻게 아느냐? 여기서 &lt;b&gt;인터럽트(Interrupt)&lt;/b&gt;가 나온다. 인터럽트는 말 그대로 &lt;b&gt;끼어들기&lt;/b&gt;다. 어떤 사건이 나면,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CPU가 &lt;b&gt;지금 하던 코드를 그 자리에서 잠깐 멈추고&lt;/b&gt;,&lt;/li&gt;
&lt;li&gt;미리 정해둔 함수(&lt;b&gt;ISR&lt;/b&gt;, 인터럽트 서비스 루틴)로 &lt;b&gt;점프&lt;/b&gt;해서 그 일을 처리하고,&lt;/li&gt;
&lt;li&gt;다 끝나면 &lt;b&gt;원래 멈췄던 자리로 복귀&lt;/b&gt;해서 하던 걸 이어서 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인트는 CPU가 &quot;언제 사건이 나나?&quot; 하고 지켜보고 있을 필요가 없다는 거다. 사건이 나면 하드웨어가 알아서 CPU를 불러준다. 이걸 &lt;b&gt;폴링(polling)&lt;/b&gt;이랑 비교하면 확 와닿는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;polling-vs-interrupt.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQQIXx/dJMcac4VtLd/6TS8zuYsYFPc0e7ZhM4zy1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQQIXx/dJMcac4VtLd/6TS8zuYsYFPc0e7ZhM4zy1/tfile.svg&quot; data-alt=&quot;폴링은 &amp;quot;다 됐어?&amp;quot;를 계속 물어보느라 CPU를 낭비하고, 인터럽트는 사건이 날 때만 잠깐 처리한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQQIXx/dJMcac4VtLd/6TS8zuYsYFPc0e7ZhM4zy1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQQIXx%2FdJMcac4VtLd%2F6TS8zuYsYFPc0e7ZhM4zy1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;400&quot; data-filename=&quot;polling-vs-interrupt.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;폴링은 &quot;다 됐어?&quot;를 계속 물어보느라 CPU를 낭비하고, 인터럽트는 사건이 날 때만 잠깐 처리한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;폴링&lt;/b&gt; : while 루프 돌면서 계속 &quot;다 됐어? 아니. 다 됐어? 아니&amp;hellip;&quot; 하고 &lt;b&gt;직접 물어본다.&lt;/b&gt; 물어보는 동안 CPU가 계속 붙잡혀 있으니 낭비가 크다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트&lt;/b&gt; : 평소엔 딴 일 하다가, 사건이 나면 &lt;b&gt;알아서 불러준다.&lt;/b&gt; CPU 낭비가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트를 쓰려면 두 개의 스위치를 알아야 한다. &lt;code&gt;sei()&lt;/code&gt;는 &lt;b&gt;전역 인터럽트 허용&lt;/b&gt;(켜기), &lt;code&gt;cli()&lt;/code&gt;는 &lt;b&gt;전역 인터럽트 금지&lt;/b&gt;(끄기)다. sei()를 안 해주면 아무리 설정해도 인터럽트가 안 걸리니까 이거 빼먹으면 안 된다. (나도 여기서 한참 헤맸다 ㅡㅡ;;;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실제 처리 함수는 &lt;code&gt;ISR(벡터명){ &amp;hellip; }&lt;/code&gt; 형태로 쓴다. 예를 들어 Timer0 오버플로용 핸들러는 이렇게 생겼다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;ISR(TIMER0_OVF_vect)
{
    // 타이머0이 오버플로 날 때마다 자동으로 여기로 점프한다
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드로 보자 &amp;mdash; delay 없이 LED 깜빡이기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 진짜다. 목표는 &lt;b&gt;delay 없이&lt;/b&gt; Timer0 오버플로 인터럽트로 LED를 일정 주기로 깜빡이는 거다. 아이디어는 위에서 말한 그대로다. &lt;b&gt;오버플로가 N번 쌓일 때마다 LED를 토글&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 타이머와 인터럽트를 설정하는 부분이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;volatile unsigned char count = 0;   // 오버플로 횟수 세는 변수

void Timer0_Init(void)
{
    TCCR0  = (1&amp;lt;&amp;lt;CS02)|(1&amp;lt;&amp;lt;CS00);   // 프리스케일러 1024로 클럭 분주
    TIMSK  = (1&amp;lt;&amp;lt;TOIE0);            // Timer0 오버플로 인터럽트 허용
    sei();                         // 전역 인터럽트 ON
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;TCCR0&lt;/code&gt; : Timer0의 동작을 정하는 레지스터. &lt;code&gt;CS02&lt;/code&gt;, &lt;code&gt;CS00&lt;/code&gt; 비트를 세우면 프리스케일러가 &lt;b&gt;1024&lt;/b&gt;로 설정된다. (즉 클럭을 1024로 나눠서 천천히 센다.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TIMSK&lt;/code&gt; : 어떤 타이머 인터럽트를 쓸지 켜는 레지스터. &lt;code&gt;TOIE0&lt;/code&gt;는 &lt;b&gt;T&lt;/b&gt;imer&lt;b&gt;0&lt;/b&gt; &lt;b&gt;O&lt;/b&gt;ver&lt;b&gt;f&lt;/b&gt;low &lt;b&gt;I&lt;/b&gt;nterrupt &lt;b&gt;E&lt;/b&gt;nable, 즉 &quot;Timer0 오버플로 인터럽트를 켠다&quot;는 뜻이다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sei()&lt;/code&gt; : 이걸 해줘야 전역 인터럽트가 실제로 동작한다. 아까 말한 그거다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 오버플로가 날 때마다 자동으로 불려가는 ISR이다.&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;ISR(TIMER0_OVF_vect)
{
    count++;                    // 오버플로 한 번 더 났다

    if (count &amp;gt;= N)             // N번 쌓이면
    {
        count = 0;             // 카운트 초기화
        LED ^= 1;              // LED 토글 (^= 1 은 0&amp;harr;1 뒤집기)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타이머가 넘칠 때마다 CPU가 잠깐 여기로 들어와서 &lt;code&gt;count&lt;/code&gt;를 하나 올리고 바로 나간다. 그러다 &lt;code&gt;count&lt;/code&gt;가 N에 도달하면 그때 LED를 뒤집고 카운트를 0으로 되돌린다. N값을 조절하면 깜빡이는 주기가 바뀐다. (한 틱 시간 &amp;times; 256 &amp;times; N 이 대략 반주기가 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 여기가 진짜 하고 싶었던 얘기다. &lt;b&gt;main은 이렇게 생겼다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void main(void)
{
    DDRB = 0xFF;        // LED 핀 출력 설정 (예시)
    Timer0_Init();      // 타이머 + 인터럽트 세팅

    while(1)
    {
        // 여기선 LED 깜빡임에 대해 아무것도 안 한다!
        // 버튼 읽기, 센서 처리, 통신 등 '딴 일'을 마음껏 한다
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보이는가. &lt;code&gt;while(1)&lt;/code&gt; 안에 &lt;b&gt;LED 관련 코드가 한 줄도 없다.&lt;/b&gt; &lt;code&gt;delay_ms&lt;/code&gt;도 없다. LED 깜빡임은 전부 인터럽트가 뒤에서 알아서 처리하고, main은 그동안 다른 일에 집중할 수 있다. 이게 아까 delay 코드랑 결정적으로 다른 점이다. &lt;b&gt;시간 재기를 하드웨어에 떠넘기고 CPU는 자유로워진 것.&lt;/b&gt; 처음 이 구조를 이해했을 때 좀 감동했다 ^^&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;ISR 짤 때 딱 하나 기억할 것&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ISR은 최대한 짧게 짜라.&lt;/b&gt; 안에서 오래 걸리는 일(긴 delay, 복잡한 계산, 통신 대기 등)을 하면 그동안 다른 인터럽트도 밀리고 시스템 전체가 버벅인다. ISR 안에서는 플래그 하나 세우거나 변수 하나 올리는 정도로 &lt;b&gt;짧게 처리하고 얼른 빠져나오는 게&lt;/b&gt; 정석이다. 무거운 일은 main의 while 루프에서 그 플래그 보고 처리하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리하면&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;타이머&lt;/b&gt; = CPU와 별개로 도는 하드웨어 카운터. &lt;code&gt;TCNT&lt;/code&gt;가 0&amp;rarr;TOP&amp;rarr;0 반복하고, 넘칠 때 &lt;b&gt;오버플로 이벤트&lt;/b&gt;가 난다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프리스케일러&lt;/b&gt;로 세는 속도를 조절한다. 한 틱 시간 = 프리스케일러 &amp;divide; F_CPU.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트&lt;/b&gt; = 사건이 나면 하던 일 멈추고 &lt;b&gt;ISR&lt;/b&gt;로 점프 &amp;rarr; 처리 &amp;rarr; 원래 자리 복귀.&lt;/li&gt;
&lt;li&gt;폴링은 계속 물어봐서 CPU 낭비, 인터럽트는 사건 날 때만 불러줘서 낭비 없음.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sei()&lt;/code&gt;로 전역 인터럽트 켜고, &lt;code&gt;ISR(TIMER0_OVF_vect){&amp;hellip;}&lt;/code&gt;로 핸들러 작성. ISR은 &lt;b&gt;짧게.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 I2C, SPI, UART, ADC, PWM에 이어 타이머/인터럽트까지 정리했다. 돌아보니 통신도, 변환도, PWM도 결국 이 타이머랑 인터럽트 위에 얹혀 있던 거더라. 마이컴 기초 시리즈가 얼추 한 바퀴 돈 느낌이다. 다음엔 이걸 다 엮어서 뭔가 하나 제대로 만들어보든가 해야겠다.&lt;/p&gt;</description>
      <category>프로그래밍/마이컴</category>
      <category>AVR</category>
      <category>ISR</category>
      <category>마이컴</category>
      <category>인터럽트</category>
      <category>임베디드</category>
      <category>타이머</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/164</guid>
      <comments>https://manggsoft.tistory.com/164#entry164comment</comments>
      <pubDate>Sun, 19 Jul 2026 05:26:24 +0900</pubDate>
    </item>
    <item>
      <title>PWM (펄스폭 변조)</title>
      <link>https://manggsoft.tistory.com/163</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 통신 쪽(I2C, SPI, UART)이랑 &lt;a href=&quot;adc.html&quot;&gt;ADC&lt;/a&gt;까지 정리했으니, 이번엔 방향을 좀 틀어서 &lt;b&gt;PWM&lt;/b&gt;을 정리해본다. ADC가 바깥 세상의 아날로그 값을 마이컴 안으로 &lt;i&gt;읽어들이는&lt;/i&gt; 거였다면, PWM은 반대로 마이컴이 아날로그처럼 바깥으로 &lt;i&gt;내보내는&lt;/i&gt; 느낌이라 짝처럼 묶어서 보기 좋더라.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일단 이 궁금증부터&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LED 밝기를 절반만 켜고 싶다. 모터를 천천히만 돌리고 싶다. 그런데 마이컴 핀이 내보낼 수 있는 건 &lt;b&gt;0V(LOW)&lt;/b&gt; 아니면 &lt;b&gt;5V(HIGH)&lt;/b&gt;, 딱 두 가지뿐이다. 디지털이니까. 그럼 그 중간인 &quot;반쯤&quot;은 대체 어떻게 만들지? 나는 처음에 무슨 볼륨 노브처럼 전압을 슬슬 낮춰주는 뭔가가 따로 있는 줄 알았다 ㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답은 좀 얍삽하다(?). &lt;b&gt;아주 빠르게 껐다 켰다를 반복&lt;/b&gt;하면서, &quot;켜져 있는 시간의 비율&quot;로 평균 전압을 만드는 거다. 절반만 켜고 싶으면 절반의 시간만 HIGH로 두면 된다. 이렇게 &lt;b&gt;켜짐/꺼짐의 폭을 조절&lt;/b&gt;해서 원하는 세기를 만드는 게 바로 PWM이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;용어부터 풀어보자&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PWM은 &lt;b&gt;Pulse Width Modulation&lt;/b&gt;, 우리말로 &lt;b&gt;펄스폭 변조&lt;/b&gt;다. 이름 그대로 &quot;펄스(HIGH로 튀어나온 신호)의 폭(넓이)을 변조(조절)한다&quot;는 뜻이다. &quot;피-더블유-엠&quot;이라고 그냥 읽으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 규칙이 하나 있다. &lt;b&gt;주기(한 번 껐다 켜지는 데 걸리는 시간)는 고정&lt;/b&gt;해두고, 그 한 주기 안에서 &lt;b&gt;HIGH로 켜져 있는 시간만 늘렸다 줄였다&lt;/b&gt; 한다는 거다. 켜짐과 꺼짐이 세트로 한 번 도는 게 한 주기고, 그 주기가 1초에 몇 번 도느냐가 주파수다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pwm-anatomy.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB2rBX/dJMcaixmh3F/KDTK0iQN1Bmi35YUIYFeqK/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB2rBX/dJMcaixmh3F/KDTK0iQN1Bmi35YUIYFeqK/tfile.svg&quot; data-alt=&quot;한 주기 = ON시간 + OFF시간. 주기는 그대로 두고 ON시간(펄스 폭)만 조절한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB2rBX/dJMcaixmh3F/KDTK0iQN1Bmi35YUIYFeqK/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB2rBX%2FdJMcaixmh3F%2FKDTK0iQN1Bmi35YUIYFeqK%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;340&quot; data-filename=&quot;pwm-anatomy.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한 주기 = ON시간 + OFF시간. 주기는 그대로 두고 ON시간(펄스 폭)만 조절한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;듀티비(duty cycle)가 진짜 주인공&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 제일 중요한 놈이 &lt;b&gt;듀티비(duty cycle)&lt;/b&gt;다. 한 주기 중에 &lt;b&gt;HIGH로 켜져 있는 시간의 비율(%)&lt;/b&gt;을 말한다. 앞 그림에 있던 그 공식이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;듀티비 = (ON 시간 / 전체 주기) &amp;times; 100%&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 듀티비가 결국 &lt;b&gt;평균 전압&lt;/b&gt;을 결정한다. 5V 기준으로 계산하면 이렇게 된다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;듀티비&lt;/th&gt;
&lt;th&gt;평균 전압 (5V 기준)&lt;/th&gt;
&lt;th&gt;체감&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;25%&lt;/th&gt;
&lt;td&gt;&amp;asymp; 1.25V&lt;/td&gt;
&lt;td&gt;LED 어둑, 모터 느릿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;50%&lt;/th&gt;
&lt;td&gt;&amp;asymp; 2.5V&lt;/td&gt;
&lt;td&gt;딱 절반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;75%&lt;/th&gt;
&lt;td&gt;&amp;asymp; 3.75V&lt;/td&gt;
&lt;td&gt;LED 밝음, 모터 빠릿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;100%&lt;/th&gt;
&lt;td&gt;5V&lt;/td&gt;
&lt;td&gt;계속 켜짐 (그냥 HIGH)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산도 간단하다. &lt;b&gt;평균 전압 = 전원 전압 &amp;times; 듀티비&lt;/b&gt;. 듀티 25%면 5V &amp;times; 0.25 = 1.25V다. 이 평균값이 LED한테는 &lt;b&gt;밝기&lt;/b&gt;로, 모터한테는 &lt;b&gt;속도&lt;/b&gt;로 느껴진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pwm-duty.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFXwrH/dJMb99NQSsl/SsTueHXqadUckr3KLVFkq1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFXwrH/dJMb99NQSsl/SsTueHXqadUckr3KLVFkq1/tfile.svg&quot; data-alt=&quot;세 파형 모두 주기(가로 폭)는 똑같다. 파란 칸(HIGH 시간)이 넓어질수록 평균 전압(주황 점선)이 올라간다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFXwrH/dJMb99NQSsl/SsTueHXqadUckr3KLVFkq1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFXwrH%2FdJMb99NQSsl%2FSsTueHXqadUckr3KLVFkq1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;420&quot; data-filename=&quot;pwm-duty.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;세 파형 모두 주기(가로 폭)는 똑같다. 파란 칸(HIGH 시간)이 넓어질수록 평균 전압(주황 점선)이 올라간다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;근데 이게 왜 되는 거지?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 처음엔 &quot;껐다 켰다 하면 깜빡거리기만 하지 어떻게 중간 밝기가 되냐&quot;가 이해가 안 됐다. 포인트는 &lt;b&gt;속도&lt;/b&gt;다. 스위칭을 &lt;b&gt;눈이나 모터가 도저히 못 따라올 만큼 빠르게&lt;/b&gt;(보통 수백 Hz에서 수십 kHz) 반복하면, 사람 눈이나 모터의 관성이 그 깜빡임을 하나하나 못 쫓아가고 그냥 &lt;b&gt;평균값으로 뭉뚱그려 느끼게&lt;/b&gt; 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형광등이 사실은 미친 듯이 깜빡이는데 우리 눈엔 그냥 계속 켜진 걸로 보이는 거랑 비슷하다. 모터도 마찬가지로, 전기가 워낙 빨리 끊겼다 이어지니까 회전 관성이 그걸 평균으로 받아서 &quot;적당한 속도&quot;로 돈다. 그래서 PWM에서 &lt;b&gt;주파수를 충분히 높게&lt;/b&gt; 잡는 게 중요하다. 너무 낮으면 LED가 눈에 띄게 깜빡거리거나 모터가 덜덜거린다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AVR에서는 어떻게 만드나 (타이머)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 소프트웨어로 &lt;code&gt;PORT&lt;/code&gt; 켰다 껐다 &lt;code&gt;delay&lt;/code&gt; 주면서 직접 만들 수도 있긴 한데, 그러면 CPU가 그 짓만 하고 있어야 해서 낭비다. 그래서 AVR은 &lt;b&gt;타이머(Timer)&lt;/b&gt;가 하드웨어로 알아서 PWM을 뽑아준다. 우리는 레지스터 몇 개만 세팅하면 끝이고, 그 뒤론 CPU가 다른 일 해도 핀에서 파형이 계속 나온다. 이게 진짜 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PWM에 관여하는 레지스터를 정리하면 이렇다. (Timer0 기준으로 설명한다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;WGM 비트&lt;/b&gt; (&lt;code&gt;TCCR0&lt;/code&gt; 안) : 타이머 동작 모드를 고른다. PWM을 쓰려면 &lt;b&gt;Fast PWM&lt;/b&gt;이나 &lt;b&gt;Phase-correct PWM&lt;/b&gt; 모드로 맞춘다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;COM 비트&lt;/b&gt; (&lt;code&gt;TCCR0&lt;/code&gt; 안) : 출력핀(&lt;code&gt;OCn&lt;/code&gt;)을 어떻게 토글할지. 보통 &quot;비교값 만나면 LOW로&quot; 하는 non-inverting 모드를 쓴다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CS 비트&lt;/b&gt; (&lt;code&gt;TCCR0&lt;/code&gt; 안) : 프리스케일러. 타이머 클럭을 몇으로 나눌지 정해서 &lt;b&gt;PWM 주파수&lt;/b&gt;를 조절한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OCR0 레지스터&lt;/b&gt; : &lt;b&gt;비교값&lt;/b&gt;. 이게 바로 &lt;b&gt;듀티비를 정하는 값&lt;/b&gt;이다. 타이머가 0부터 세다가 이 값에 도달하면 핀을 내린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PWM 주파수는 이 공식으로 정해진다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;PWM 주파수 = F_CPU / (프리스케일러 &amp;times; (TOP + 1))&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8비트 타이머면 TOP이 255라서 &lt;code&gt;(TOP+1)&lt;/code&gt;은 256이 된다. 여기까지가 세팅이고, 실제로 &lt;b&gt;밝기를 바꾸는 건 오로지 &lt;code&gt;OCR0&lt;/code&gt; 값 하나&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드로 보자 (Timer0, 8비트 Fast PWM)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로 하면 복잡하니 코드가 마음 편하다. Timer0을 Fast PWM으로 세팅하는 예시다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void PWM_Init(void)
{
    // OC0 핀(PWM 출력)을 출력으로. (ATmega128 기준 PB4)
    DDRB |= (1 &amp;lt;&amp;lt; PB4);

    // Fast PWM 모드 : WGM01, WGM00 둘 다 1
    // non-inverting 출력 : COM01 = 1  (비교값 만나면 LOW)
    // 프리스케일러 8       : CS01 = 1
    TCCR0 = (1 &amp;lt;&amp;lt; WGM00) | (1 &amp;lt;&amp;lt; WGM01) | (1 &amp;lt;&amp;lt; COM01) | (1 &amp;lt;&amp;lt; CS01);

    OCR0 = 64;   // 듀티 &amp;asymp; 64/255 &amp;asymp; 25%  &amp;rarr; LED 어둑하게
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;WGM00&lt;/code&gt;+&lt;code&gt;WGM01&lt;/code&gt;로 Fast PWM 모드가 되고, &lt;code&gt;COM01&lt;/code&gt;로 &quot;OCR0에 도달하면 출력핀을 LOW로 내리는&quot; 동작이 켜진다. 즉 타이머가 0&amp;rarr;255를 계속 반복하는데, &lt;b&gt;0부터 OCR0까지는 HIGH, OCR0 넘으면 255까지는 LOW&lt;/b&gt;가 된다. 그래서 &lt;code&gt;OCR0&lt;/code&gt;가 클수록 HIGH 구간이 길어지고 = 듀티가 커지고 = 밝아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 &lt;b&gt;세팅은 한 번만 하고, 그 다음부턴 &lt;code&gt;OCR0&lt;/code&gt; 값만 바꾸면 밝기/속도가 실시간으로 바뀐다&lt;/b&gt;는 거다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;void main(void)
{
    PWM_Init();

    while (1)
    {
        OCR0 = 64;    // 듀티 25%  (5V &amp;times; 0.25 &amp;asymp; 1.25V) &amp;rarr; 어둑
        // OCR0 = 128; // 듀티 50%  (&amp;asymp; 2.5V)  &amp;rarr; 절반
        // OCR0 = 191; // 듀티 75%  (&amp;asymp; 3.75V) &amp;rarr; 밝음
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;code&gt;OCR0&lt;/code&gt; 한 줄만 &lt;code&gt;0&lt;/code&gt;부터 &lt;code&gt;255&lt;/code&gt; 사이로 바꿔주면 밝기가 쭉 조절된다. 만약 가변저항 값을 ADC로 읽어서 그 값을 &lt;code&gt;OCR0&lt;/code&gt;에 그대로 넣어주면? 노브를 돌리는 대로 LED 밝기가 따라오는 디머(dimmer)가 된다. ADC랑 PWM이 이렇게 만난다 ^^&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어디에 쓰나&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;LED 디밍&lt;/b&gt; : &lt;code&gt;OCR&lt;/code&gt; 값만 바꿔서 밝기 조절. 부드럽게 밝아졌다 어두워지는 숨쉬기 효과도 이걸로 만든다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DC 모터 속도 제어&lt;/b&gt; : 듀티비로 평균 전압 = 속도 조절. (실제론 모터 전류 때문에 트랜지스터/MOSFET를 하나 끼워서 구동한다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서보모터&lt;/b&gt; : 얘는 좀 특이한데, 주기 20ms(50Hz)에 &lt;b&gt;펄스폭 1~2ms&lt;/b&gt;를 실어서 그 폭으로 &lt;b&gt;각도&lt;/b&gt;를 정한다. (밝기가 아니라 위치를 PWM으로 지정하는 케이스 &amp;mdash; 이건 나중에 따로 다뤄야겠다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리하면&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마이컴 핀은 0V/5V만 내보내지만, &lt;b&gt;빠르게 껐다 켰다&lt;/b&gt; 하면 그 평균으로 중간값을 만들 수 있다. 그게 PWM.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주기는 고정&lt;/b&gt;, 한 주기 안의 &lt;b&gt;HIGH 시간(펄스 폭)만 조절&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;듀티비 = ON시간 / 주기&lt;/b&gt;. 평균 전압 = 전원 전압 &amp;times; 듀티비. &amp;rarr; LED 밝기, 모터 속도가 된다.&lt;/li&gt;
&lt;li&gt;AVR에선 &lt;b&gt;타이머&lt;/b&gt;가 하드웨어로 만들어준다. &lt;b&gt;&lt;code&gt;OCR&lt;/code&gt; 값만 바꾸면&lt;/b&gt; 밝기/속도가 바뀐다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하다 보니 결국 PWM은 &lt;b&gt;타이머&lt;/b&gt;가 다 해주는 거였다. 주파수도 프리스케일러+TOP으로 정하고, 듀티도 비교값으로 정하고&amp;hellip; 죄다 타이머 이야기다. 그래서 다음엔 &lt;b&gt;타이머와 인터럽트&lt;/b&gt;를 제대로 파봐야겠다. PWM도 결국 타이머로 만드는 거니까, 순서상 그게 맞는 것 같다.&lt;/p&gt;</description>
      <category>프로그래밍/마이컴</category>
      <category>AVR</category>
      <category>PWM</category>
      <category>마이컴</category>
      <category>임베디드</category>
      <category>타이머</category>
      <category>펄스폭변조</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/163</guid>
      <comments>https://manggsoft.tistory.com/163#entry163comment</comments>
      <pubDate>Sun, 19 Jul 2026 05:21:32 +0900</pubDate>
    </item>
    <item>
      <title>ADC (아날로그 읽기)</title>
      <link>https://manggsoft.tistory.com/162</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;UART, I2C, SPI 통신 글은 이미 다 써버렸다. 근데 이번엔 통신 얘기가 아니다. 지금까지 다룬 건 죄다 &lt;b&gt;디지털 신호(0/1)&lt;/b&gt;였는데, 세상엔 0과 1로 딱 안 떨어지는 값이 훨씬 많더라. 온도, 밝기, 가변저항 돌린 정도&amp;hellip; 이런 건 전부 &lt;b&gt;연속적인 아날로그 전압&lt;/b&gt;이다. 오늘은 이걸 마이컴이 어떻게 읽는지, &lt;b&gt;ADC&lt;/b&gt;를 정리해본다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일단 문제부터&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이컴은 기본적으로 &lt;b&gt;0 아니면 1&lt;/b&gt;밖에 모른다. 핀에 전압이 걸렸냐(HIGH) 안 걸렸냐(LOW), 딱 두 가지다. 그런데 예를 들어 가변저항을 천천히 돌리면 핀에 걸리는 전압이 &lt;b&gt;0V에서 5V까지 스르륵&lt;/b&gt; 바뀐다. 2.3V, 2.31V, 2.317V&amp;hellip; 무한히 잘게 쪼갤 수 있는 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 마이컴한테 &quot;지금 몇 볼트야?&quot; 하고 물어보면, 디지털만 아는 녀석이 답을 못 한다. 그래서 &lt;b&gt;아날로그 전압을 숫자로 바꿔주는 통역기&lt;/b&gt;가 필요하다. 그게 ADC다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;용어적 설명부터&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADC는 &lt;b&gt;Analog to Digital Converter&lt;/b&gt;, 말 그대로 &quot;아날로그를 디지털로 바꾸는 변환기&quot;다. &quot;에이-디-씨&quot;라고 읽으면 된다. 반대로 디지털을 아날로그로 뱉는 DAC라는 것도 있는데 그건 나중에 얘기하고, 오늘은 &lt;b&gt;읽는 쪽(ADC)&lt;/b&gt;만 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADC를 이해하려면 딱 &lt;b&gt;3가지 용어&lt;/b&gt;만 잡으면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;해상도(resolution)&lt;/b&gt; : 전압을 몇 단계로 쪼개서 표현하냐. AVR은 보통 &lt;b&gt;10비트&lt;/b&gt;라서 &lt;b&gt;0 ~ 1023&lt;/b&gt;, 즉 &lt;b&gt;1024단계&lt;/b&gt;로 나눈다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기준전압(Vref)&lt;/b&gt; : 측정의 &quot;만점&quot; 기준. 예를 들어 5V로 잡으면, &quot;5V가 곧 1023(만점)&quot;이라는 뜻이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변환식&lt;/b&gt; : 실제로 얼마가 나오냐. &lt;b&gt;디지털값 = (Vin / Vref) &amp;times; 1023&lt;/b&gt;. 거꾸로 전압을 알고 싶으면 &lt;b&gt;Vin = 디지털값 &amp;times; Vref / 1023&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;adc-mapping.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjhhbg/dJMcaalHkaB/Wd6Wfq6E90wIRnHXC5GjG0/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjhhbg/dJMcaalHkaB/Wd6Wfq6E90wIRnHXC5GjG0/tfile.svg&quot; data-alt=&quot;0 ~ Vref 사이의 전압을 0 ~ 1023 숫자에 나눠 대응시킨다. 전압이 높을수록 값도 커진다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjhhbg/dJMcaalHkaB/Wd6Wfq6E90wIRnHXC5GjG0/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjhhbg%2FdJMcaalHkaB%2FWd6Wfq6E90wIRnHXC5GjG0%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;380&quot; data-filename=&quot;adc-mapping.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;0 ~ Vref 사이의 전압을 0 ~ 1023 숫자에 나눠 대응시킨다. 전압이 높을수록 값도 커진다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;숫자로 감 잡기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로만 하면 안 와닿으니 숫자를 넣어보자. &lt;b&gt;Vref = 5V, 10비트(0~1023)&lt;/b&gt;라고 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 칸이 몇 볼트냐? &amp;rarr; 5V를 1024단계로 나누니까 &lt;b&gt;5V / 1024 &amp;asymp; 약 4.9mV&lt;/b&gt;. 즉 디지털값이 1 올라갈 때마다 약 4.9mV씩 차이 난다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;0V&lt;/b&gt;를 넣으면 &amp;rarr; &lt;b&gt;0&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2.5V&lt;/b&gt;(절반)를 넣으면 &amp;rarr; (2.5 / 5) &amp;times; 1023 &amp;asymp; &lt;b&gt;512&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;5V&lt;/b&gt;(만점)를 넣으면 &amp;rarr; &lt;b&gt;1023&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딱 절반 넣으면 딱 절반 값이 나온다. 처음엔 이게 왜 1024가 아니라 1023을 곱하나 싶어서 좀 헷갈렸는데, &lt;b&gt;단계는 1024개지만 표현할 수 있는 최댓값(번호)은 0부터 세서 1023&lt;/b&gt;이라 그렇다. (0번 칸이 있으니까.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떻게 숫자로 바뀌나 &amp;mdash; 표본화와 양자화&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADC가 전압을 숫자로 바꾸는 과정은 크게 두 단계다. 이름은 거창한데 뜻은 별거 없다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;표본화(sampling)&lt;/b&gt; : 연속으로 흐르는 전압을 &lt;b&gt;일정 간격으로 콕콕 찍는다.&lt;/b&gt; 계속 보는 게 아니라 순간순간 사진 찍듯 값을 잡는 거다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;양자화(quantization)&lt;/b&gt; : 찍은 값을 &lt;b&gt;정해진 계단값 중 가장 가까운 걸로 반올림&lt;/b&gt;한다. 5V/1024 칸 중에 제일 가까운 칸으로 몰아준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아무리 매끈한 아날로그 곡선이라도, ADC를 거치고 나면 &lt;b&gt;계단 모양으로 근사&lt;/b&gt;된 값이 나온다. 해상도가 낮으면(계단이 크면) 실제 곡선이랑 좀 어긋나고, 높으면(계단이 촘촘하면) 원본에 가까워진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;adc-quantize.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl02Un/dJMcagM7FCk/5KioGprUOS9d1uKYUSp3o0/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl02Un/dJMcagM7FCk/5KioGprUOS9d1uKYUSp3o0/tfile.svg&quot; data-alt=&quot;연속 전압을 일정 간격으로 찍어(표본화) 가까운 계단값으로 반올림(양자화)한다. 그래서 계단 근사가 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl02Un/dJMcagM7FCk/5KioGprUOS9d1uKYUSp3o0/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl02Un%2FdJMcagM7FCk%2F5KioGprUOS9d1uKYUSp3o0%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;400&quot; data-filename=&quot;adc-quantize.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;연속 전압을 일정 간격으로 찍어(표본화) 가까운 계단값으로 반올림(양자화)한다. 그래서 계단 근사가 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핀은 여러 개, 채널로 고른다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아날로그 입력핀은 보통 하나가 아니다. AVR을 보면 &lt;code&gt;ADC0&lt;/code&gt;, &lt;code&gt;ADC1&lt;/code&gt;, &lt;code&gt;ADC2&lt;/code&gt;&amp;hellip; 여러 개가 있다. 그런데 실제 변환기(ADC 회로)는 칩 안에 &lt;b&gt;딱 하나&lt;/b&gt;다. 그럼 어떻게 여러 핀을 읽나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MUX(멀티플렉서)&lt;/b&gt;라는 스위치로 &quot;이번엔 ADC0 읽어줘&quot;, &quot;다음엔 ADC3 읽어줘&quot; 하고 &lt;b&gt;한 번에 하나씩 골라서&lt;/b&gt; 변환기에 연결한다. 그래서 가변저항은 ADC0, 조도센서는 ADC1&amp;hellip; 이렇게 꽂아두고 채널만 바꿔가며 돌려 읽으면 된다. 이 채널 선택은 코드에서 레지스터로 지정한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AVR 코드로 보자&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실제 레지스터를 만져보자. 통신 글들에서 핀을 직접 두드렸던 것처럼, ADC도 결국 &lt;b&gt;레지스터 몇 개 설정 &amp;rarr; 변환 시작 &amp;rarr; 끝날 때까지 대기 &amp;rarr; 결과 읽기&lt;/b&gt; 순서다. 관련 레지스터부터 정리한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;레지스터&lt;/th&gt;
&lt;th&gt;하는 일&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;ADMUX&lt;/th&gt;
&lt;td&gt;기준전압 선택(REFS 비트) + 읽을 채널 선택(MUX 비트)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;ADCSRA&lt;/th&gt;
&lt;td&gt;ADC 켜기(ADEN), 변환 시작(ADSC), 클럭 프리스케일러(ADPS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;ADC (ADCH:ADCL)&lt;/th&gt;
&lt;td&gt;변환 결과가 담기는 16비트 값. 여기서 최종 0~1023을 읽는다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 초기화다. 기준전압은 &lt;b&gt;AVCC(보통 5V)&lt;/b&gt;를 쓰고, 변환 클럭이 너무 빠르면 결과가 부정확해서 &lt;b&gt;프리스케일러를 128&lt;/b&gt;로 팍 줄여준다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void ADC_init(void)
{
    // 기준전압 = AVCC (REFS0 = 1)
    ADMUX = (1 &amp;lt;&amp;lt; REFS0);

    // ADC 켜고(ADEN), 프리스케일러 128 (ADPS2:0 = 111)
    ADCSRA = (1 &amp;lt;&amp;lt; ADEN) | (1 &amp;lt;&amp;lt; ADPS2) | (1 &amp;lt;&amp;lt; ADPS1) | (1 &amp;lt;&amp;lt; ADPS0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 실제로 한 채널을 읽는 함수다. &lt;b&gt;채널 선택 &amp;rarr; 변환 시작 &amp;rarr; 끝날 때까지 대기 &amp;rarr; 결과 리턴&lt;/b&gt;, 이 흐름 그대로다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;unsigned int ADC_read(unsigned char ch)
{
    // 하위 4비트만 채널 번호로 갈아끼운다 (상위 비트는 그대로 유지)
    ADMUX = (ADMUX &amp;amp; 0xF0) | (ch &amp;amp; 0x0F);

    // 변환 시작
    ADCSRA |= (1 &amp;lt;&amp;lt; ADSC);

    // ADSC가 자동으로 0이 되면 변환 끝 &amp;rarr; 그때까지 대기
    while (ADCSRA &amp;amp; (1 &amp;lt;&amp;lt; ADSC));

    return ADC;   // 0 ~ 1023
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인트는 &lt;code&gt;while (ADCSRA &amp;amp; (1 &amp;lt;&amp;lt; ADSC));&lt;/code&gt; 이 한 줄이다. &lt;b&gt;변환을 시작하면 ADSC 비트가 1이 되고, 변환이 끝나면 하드웨어가 알아서 0으로 내려준다.&lt;/b&gt; 그래서 0이 될 때까지 기다리기만 하면 된다. I2C/SPI에서 클럭 굴리며 비트 세던 것보다 오히려 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에 그냥 &lt;code&gt;ADC&lt;/code&gt;라고 쓰면 결과 16비트를 통째로 읽어준다. 컴파일러가 &lt;code&gt;ADCL&lt;/code&gt;, &lt;code&gt;ADCH&lt;/code&gt;를 알아서 합쳐주는 거다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;주의 : 만약 &lt;code&gt;ADCL&lt;/code&gt;, &lt;code&gt;ADCH&lt;/code&gt;를 &lt;b&gt;직접 따로 읽는다면 반드시 &lt;code&gt;ADCL&lt;/code&gt;(하위)을 먼저, &lt;code&gt;ADCH&lt;/code&gt;(상위)를 나중에&lt;/b&gt; 읽어야 한다. 순서를 바꾸면 값이 갱신되며 꼬인다. &lt;code&gt;ADC&lt;/code&gt;로 한 번에 읽으면 이 걱정은 없다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;실제로 써먹으면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽은 0~1023 값 하나로 할 수 있는 게 은근 많다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가변저항&lt;/b&gt; : 돌린 만큼 0~1023이 바뀌니 볼륨 노브, 밝기 조절 같은 데 쓴다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조도센서(CDS)&lt;/b&gt; : 밝으면 저항이 변해서 전압이 바뀐다 &amp;rarr; 밝기 측정.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;온도센서&lt;/b&gt; : 온도에 비례하는 전압을 뱉는 센서를 읽어서 온도로 환산.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 응용하면 &quot;어두워지면 LED 켜기&quot;, &quot;가변저항으로 모터 속도 조절&quot; 같은 게 다 ADC 값 하나에서 출발한다. 값을 그대로 쓰거나, 아까 그 변환식으로 실제 전압/물리량으로 바꿔 쓰면 된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void main(void)
{
    unsigned int val;

    ADC_init();

    while (1)
    {
        val = ADC_read(0);      // ADC0 채널(예: 가변저항) 읽기

        if (val &amp;gt; 512) LED_ON;  // 절반(약 2.5V) 넘으면 LED 켜기
        else           LED_OFF;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리하면&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ADC = 아날로그 전압을 디지털 숫자로 바꾸는 변환기. 센서값을 읽으려면 필수다.&lt;/li&gt;
&lt;li&gt;핵심 3가지 : &lt;b&gt;해상도&lt;/b&gt;(AVR 10비트=0~1023), &lt;b&gt;기준전압(Vref)&lt;/b&gt;, &lt;b&gt;변환식&lt;/b&gt;(디지털값 = Vin/Vref &amp;times; 1023).&lt;/li&gt;
&lt;li&gt;과정은 &lt;b&gt;표본화&lt;/b&gt;(일정 간격으로 찍기) + &lt;b&gt;양자화&lt;/b&gt;(가까운 계단값으로 반올림). 그래서 계단 근사가 된다.&lt;/li&gt;
&lt;li&gt;여러 핀은 &lt;b&gt;MUX로 채널을 골라&lt;/b&gt; 하나씩 읽는다.&lt;/li&gt;
&lt;li&gt;코드는 &lt;code&gt;ADMUX&lt;/code&gt;로 기준전압/채널, &lt;code&gt;ADCSRA&lt;/code&gt;로 켜고 시작, &lt;b&gt;ADSC가 0되면 끝&lt;/b&gt;, 결과는 &lt;code&gt;ADC&lt;/code&gt;에서 읽기.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신 3종(UART/I2C/SPI) 정리하고 나서 아날로그까지 오니까, 이제 센서 웬만한 건 다 읽을 수 있게 됐다. 읽는 건 이걸로 됐으니, 다음엔 반대로 &lt;b&gt;아날로그처럼 출력하는 PWM&lt;/b&gt;을 정리해봐야겠다. (LED 밝기 조절이나 모터 속도, 이게 다 PWM이더라.)&lt;/p&gt;</description>
      <category>프로그래밍/마이컴</category>
      <category>ADC</category>
      <category>AVR</category>
      <category>마이컴</category>
      <category>센서</category>
      <category>아날로그</category>
      <category>임베디드</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/162</guid>
      <comments>https://manggsoft.tistory.com/162#entry162comment</comments>
      <pubDate>Sun, 19 Jul 2026 05:18:04 +0900</pubDate>
    </item>
    <item>
      <title>UART 통신</title>
      <link>https://manggsoft.tistory.com/161</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;I2C 보고 SPI 봤으니 이번엔 UART다. 사실 셋 중에 제일 처음 만나게 되는 게 이 녀석인데, &quot;시리얼 모니터에 글자 찍기&quot;가 바로 UART다. 근데 앞에 둘이랑 결정적으로 다른 점이 하나 있다. &lt;b&gt;클럭선이 없다.&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클럭선이 없다고?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I2C엔 SCL, SPI엔 SCK 라는 &lt;b&gt;클럭선&lt;/b&gt;이 있었다. 이게 &quot;지금이 1비트를 읽을 타이밍이야&quot; 하고 박자를 딱딱 찍어주는 선이었다. 그래서 둘 다 &lt;b&gt;동기식(synchronous)&lt;/b&gt; 통신이라고 불렀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 UART는 그 클럭선이 &lt;b&gt;없다.&lt;/b&gt; 그래서 &lt;b&gt;비동기(asynchronous)&lt;/b&gt;다. 이름부터가 그렇다. UART = &lt;b&gt;U&lt;/b&gt;niversal &lt;b&gt;A&lt;/b&gt;synchronous &lt;b&gt;R&lt;/b&gt;eceiver/&lt;b&gt;T&lt;/b&gt;ransmitter. 우리가 흔히 &quot;시리얼 통신&quot;, &quot;RS-232&quot; 라고 부르는 게 다 이거다. &quot;유아트&quot; 라고 읽으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 바로 드는 의문. &lt;b&gt;클럭이 없는데 대체 언제가 1비트인지 어떻게 알아?&lt;/b&gt; 이게 UART의 핵심이라 뒤에서 따로 짚는다. 결론만 먼저 말하면, &lt;b&gt;양쪽이 통신 속도를 미리 약속&lt;/b&gt;해두는 방식으로 해결한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;선은 딱 2개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UART는 데이터선이 &lt;b&gt;2개&lt;/b&gt;다. (GND 빼고)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;TX&lt;/b&gt; : Transmit. 내가 &lt;b&gt;내보내는(송신)&lt;/b&gt; 선.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RX&lt;/b&gt; : Receive. 내가 &lt;b&gt;받는(수신)&lt;/b&gt; 선.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 배선할 때 여기서 한 번 다들 삽질한다. &lt;b&gt;TX는 TX끼리, RX는 RX끼리 연결하는 게 아니다.&lt;/b&gt; 내가 내보낸 걸 상대는 받아야 하니까, &lt;b&gt;X자로 교차&lt;/b&gt;해서 이어줘야 한다. 내 TX &amp;rarr; 상대 RX, 상대 TX &amp;rarr; 내 RX. 여기에 GND만 공통으로 하나 이어주면 끝이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;uart-wiring.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1iBDs/dJMcadJsUZE/o6xkLfeH9jTgKHtImKRw1K/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1iBDs/dJMcadJsUZE/o6xkLfeH9jTgKHtImKRw1K/tfile.svg&quot; data-alt=&quot;UART 결선도. 내 TX는 상대 RX로 교차 연결. 클럭선이 없다는 게 핵심이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1iBDs/dJMcadJsUZE/o6xkLfeH9jTgKHtImKRw1K/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1iBDs%2FdJMcadJsUZE%2Fo6xkLfeH9jTgKHtImKRw1K%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;360&quot; data-filename=&quot;uart-wiring.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;UART 결선도. 내 TX는 상대 RX로 교차 연결. 클럭선이 없다는 게 핵심이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPI처럼 &lt;b&gt;전이중(full-duplex)&lt;/b&gt;이라 TX/RX가 따로 있어서 보내기와 받기를 동시에 할 수 있다. 그리고 SPI/I2C랑 다르게 &lt;b&gt;마스터/슬레이브 개념이 없다.&lt;/b&gt; 그냥 양쪽이 대등하게 각자 TX로 쏘고 RX로 받는다. 처음엔 TX끼리 이어놓고 &quot;왜 글자가 안 나오지&quot; 하고 한참 헤맸다 ㅡㅡ;;;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래서 I2C / SPI랑 뭐가 다른데?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에 둘을 봤으니 표로 비교하는 게 제일 빠르다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;I2C&lt;/th&gt;
&lt;th&gt;SPI&lt;/th&gt;
&lt;th&gt;UART&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;클럭선&lt;/th&gt;
&lt;td&gt;있음 (SCL)&lt;/td&gt;
&lt;td&gt;있음 (SCK)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;없음 (비동기)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;선 개수&lt;/th&gt;
&lt;td&gt;2선&lt;/td&gt;
&lt;td&gt;4선&lt;/td&gt;
&lt;td&gt;2선 (TX, RX)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;역할 구분&lt;/th&gt;
&lt;td&gt;마스터/슬레이브&lt;/td&gt;
&lt;td&gt;마스터/슬레이브&lt;/td&gt;
&lt;td&gt;대등 (없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;통신 방향&lt;/th&gt;
&lt;td&gt;반이중&lt;/td&gt;
&lt;td&gt;전이중&lt;/td&gt;
&lt;td&gt;전이중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;속도 약속&lt;/th&gt;
&lt;td&gt;클럭이 알아서&lt;/td&gt;
&lt;td&gt;클럭이 알아서&lt;/td&gt;
&lt;td&gt;&lt;b&gt;보드레이트로 미리&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 역시 &lt;b&gt;클럭선의 유무&lt;/b&gt;다. 클럭이 없는 대신 UART는 다른 방법으로 박자를 맞춘다. 그게 보드레이트다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클럭 없이 어떻게 비트를 나누나 &amp;mdash; 보드레이트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클럭선이 없으니 &quot;지금 읽어&quot; 하고 알려주는 신호가 없다. 그럼 어떻게 하냐면, &lt;b&gt;양쪽이 1비트에 쓸 시간을 미리 똑같이 약속&lt;/b&gt;해둔다. 이 약속한 속도가 &lt;b&gt;보드레이트(baud rate)&lt;/b&gt;다. 단위는 bps(초당 비트).&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흔히 쓰는 값: &lt;b&gt;9600&lt;/b&gt;, &lt;b&gt;115200&lt;/b&gt; bps.&lt;/li&gt;
&lt;li&gt;1비트에 쓰는 시간 = &lt;b&gt;1 / 보드레이트&lt;/b&gt;. 예를 들어 9600bps면 1비트가 약 104&amp;mu;s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 받는 쪽은 클럭을 볼 필요 없이 &lt;b&gt;&quot;신호가 시작되면 정해진 시간 간격으로 뚝뚝 끊어서 비트를 읽으면 된다.&quot;&lt;/b&gt; 양쪽이 같은 보드레이트로 맞춰놨으니 타이밍이 딱딱 들어맞는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &quot;신호가 시작되는 순간&quot;은 어떻게 아느냐? 여기서 프레임 얘기가 나온다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프레임 구조 (8N1)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평소에 아무것도 안 보낼 때, UART 라인은 &lt;b&gt;HIGH를 유지&lt;/b&gt;한다. 이걸 idle 상태라고 한다. 그러다 데이터를 보낼 때 다음 순서로 한 묶음(프레임)을 쏜다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시작비트&lt;/b&gt; (1개) : 라인을 &lt;b&gt;HIGH에서 LOW로 뚝 떨어뜨린다.&lt;/b&gt; &quot;이제 시작한다!&quot;는 신호. 받는 쪽은 이 떨어지는 순간을 보고 &quot;아 시작이구나&quot; 하고 타이머를 돌린다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터비트&lt;/b&gt; (보통 8개) : 진짜 데이터. 여기서 주의할 게, &lt;b&gt;LSB first&lt;/b&gt;다. 즉 &lt;b&gt;낮은 자리 비트부터&lt;/b&gt; 나간다. (SPI는 보통 MSB first였는데 UART는 반대라 헷갈린다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패리티비트&lt;/b&gt; (옵션) : 에러 체크용. 안 쓰는 경우가 더 많다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정지비트&lt;/b&gt; (1~2개) : 라인을 다시 &lt;b&gt;HIGH로&lt;/b&gt; 올려서 &quot;한 프레임 끝&quot; 표시.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정을 짧게 &lt;b&gt;&quot;8N1&quot;&lt;/b&gt; 이라고 적는다. &lt;b&gt;8&lt;/b&gt;비트 데이터, &lt;b&gt;N&lt;/b&gt;o 패리티, 정지비트 &lt;b&gt;1&lt;/b&gt;개. 제일 흔한 설정이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;uart-frame.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E0UWY/dJMcab52QLy/au5hqGdBz5KrgG9bbY1OeK/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E0UWY/dJMcab52QLy/au5hqGdBz5KrgG9bbY1OeK/tfile.svg&quot; data-alt=&quot;문자 'A'(0x41)를 보내는 프레임. idle(HIGH) &amp;amp;rarr; 시작(LOW) &amp;amp;rarr; 데이터 8비트 &amp;amp;rarr; 정지(HIGH).&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E0UWY/dJMcab52QLy/au5hqGdBz5KrgG9bbY1OeK/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE0UWY%2FdJMcab52QLy%2Fau5hqGdBz5KrgG9bbY1OeK%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;380&quot; data-filename=&quot;uart-frame.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;문자 'A'(0x41)를 보내는 프레임. idle(HIGH) &amp;rarr; 시작(LOW) &amp;rarr; 데이터 8비트 &amp;rarr; 정지(HIGH).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 문자 &lt;code&gt;'A'&lt;/code&gt;를 보내는 예시다. &lt;code&gt;'A'&lt;/code&gt;는 아스키로 &lt;b&gt;0x41 = 0b01000001&lt;/b&gt;인데, LSB first라서 실제 라인에는 &lt;b&gt;1, 0, 0, 0, 0, 0, 1, 0&lt;/b&gt; 순서(b0&amp;rarr;b7)로 나간다. 비트 순서가 눈으로 보던 이진수랑 뒤집혀서 나가는 게 처음엔 좀 어지럽다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제일 흔한 삽질: 보드레이트 안 맞음&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UART 하다 보면 &lt;b&gt;거의 무조건 한 번은 겪는 증상&lt;/b&gt;이 있다. 시리얼 모니터에 글자가 &lt;code&gt;?????&lt;/code&gt; 이렇게 깨진 문자로 나오는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인은 십중팔구 &lt;b&gt;양쪽 보드레이트가 안 맞아서&lt;/b&gt;다. 한쪽은 9600으로 보내는데 받는 쪽은 115200으로 읽으면, 1비트 시간이 서로 다르니까 비트를 엉뚱한 지점에서 끊어 읽는다. 그러니 글자가 와장창 깨진다. 클럭선이 없어서 순전히 시간 약속에 의존하는 UART의 &lt;b&gt;대가&lt;/b&gt;인 셈이다ㅋㅋ. 글자 깨지면 제일 먼저 &lt;b&gt;양쪽 보드레이트부터 확인&lt;/b&gt;하자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드로 보자 (AVR)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AVR에선 하드웨어 UART가 내장돼 있어서 레지스터만 세팅하면 된다. SPI 때 비트뱅잉으로 직접 두드린 것보단 오히려 편하다. 레지스터 이름부터 정리하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UBRRH / UBRRL&lt;/b&gt; : 보드레이트 설정값(16비트)을 상/하위로 나눠 넣는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UDR&lt;/b&gt; : 데이터 레지스터. 여기에 쓰면 송신, 여기서 읽으면 수신.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UCSRA&lt;/b&gt; : 상태 확인. &lt;code&gt;UDRE&lt;/code&gt;(송신버퍼 비었나), &lt;code&gt;RXC&lt;/code&gt;(수신 완료됐나) 비트를 본다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UCSRB&lt;/b&gt; : &lt;code&gt;TXEN&lt;/code&gt;(송신 켜기), &lt;code&gt;RXEN&lt;/code&gt;(수신 켜기).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UCSRC&lt;/b&gt; : 프레임 형식(데이터 비트 수, 패리티, 정지비트) 설정. 여기서 8N1을 잡는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 초기화다. 보드레이트값(UBRR)은 공식이 정해져 있다. &lt;code&gt;UBRR = F_CPU / (16 &amp;times; baud) &amp;minus; 1&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void UART_init(unsigned long baud)
{
    // 보드레이트 계산 : UBRR = F_CPU/(16*baud) - 1
    unsigned int ubrr = F_CPU / (16UL * baud) - 1;

    UBRRH = (unsigned char)(ubrr &amp;gt;&amp;gt; 8);   // 상위 8비트
    UBRRL = (unsigned char)(ubrr);         // 하위 8비트

    // 송신(TXEN), 수신(RXEN) 둘 다 켠다
    UCSRB = (1 &amp;lt;&amp;lt; TXEN) | (1 &amp;lt;&amp;lt; RXEN);

    // 프레임 형식 : 8비트 데이터, 패리티 없음, 정지 1비트 (8N1)
    UCSRC = (1 &amp;lt;&amp;lt; UCSZ1) | (1 &amp;lt;&amp;lt; UCSZ0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 한 글자 보내기. &lt;b&gt;송신 버퍼가 빌 때까지 기다렸다가&lt;/b&gt; UDR에 쓰면 된다. 버퍼가 아직 차 있는데 덮어쓰면 데이터가 날아가니까 &lt;code&gt;UDRE&lt;/code&gt; 비트를 확인하는 거다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void UART_putc(char c)
{
    // 송신 버퍼가 빌 때까지 대기 (UDRE = 1 되면 비었다는 뜻)
    while ( !(UCSRA &amp;amp; (1 &amp;lt;&amp;lt; UDRE)) );

    UDR = c;   // 버퍼 비었으니 이제 쓴다 -&amp;gt; 하드웨어가 알아서 쏴준다
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;받기는 반대다. &lt;b&gt;수신이 완료될 때까지 기다렸다가&lt;/b&gt; UDR을 읽는다. 한 프레임이 다 들어오면 &lt;code&gt;RXC&lt;/code&gt; 비트가 1이 된다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;char UART_getc(void)
{
    // 데이터가 들어올 때까지 대기 (RXC = 1 되면 도착했다는 뜻)
    while ( !(UCSRA &amp;amp; (1 &amp;lt;&amp;lt; RXC)) );

    return UDR;   // 도착했으니 읽어서 돌려준다
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패턴이 SPI 때랑 비슷하다. &lt;b&gt;플래그 비트를 &lt;code&gt;while&lt;/code&gt;로 기다렸다가 &amp;rarr; 준비되면 데이터 레지스터를 건드린다.&lt;/b&gt; 송신은 &quot;버퍼 빌 때까지&quot;, 수신은 &quot;올 때까지&quot; 기다리는 것만 다르다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문자열 출력 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 글자짜리를 만들었으니 문자열은 그냥 반복이다. 시리얼 모니터에 &lt;code&gt;Hello&lt;/code&gt; 찍는 정도는 이걸로 끝난다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void UART_puts(const char *s)
{
    while (*s)              // 널 문자('\0') 만날 때까지
        UART_putc(*s++);    // 한 글자씩 보낸다
}

void main(void)
{
    UART_init(9600);            // 보드레이트 9600으로 시작
    UART_puts(&quot;Hello UART!\r\n&quot;);

    while (1)
    {
        char c = UART_getc();   // 뭔가 들어오면
        UART_putc(c);           // 그대로 되돌려 보낸다 (에코)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC 시리얼 모니터를 열 때 &lt;b&gt;보드레이트를 꼭 9600으로 맞춰야&lt;/b&gt; 글자가 제대로 보인다. (안 맞추면 아까 그 &lt;code&gt;?????&lt;/code&gt; 향연이다.) 위 &lt;code&gt;while&lt;/code&gt; 루프는 받은 글자를 그대로 돌려보내는 &lt;b&gt;에코&lt;/b&gt;인데, 통신이 잘 되는지 확인할 때 딱 좋다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리하면&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UART = &lt;b&gt;비동기&lt;/b&gt; 직렬통신. I2C/SPI와 달리 &lt;b&gt;클럭선이 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;선은 &lt;b&gt;TX, RX 2개&lt;/b&gt; + GND. &lt;b&gt;X자로 교차&lt;/b&gt; 연결(내 TX &amp;rarr; 상대 RX).&lt;/li&gt;
&lt;li&gt;클럭이 없는 대신 &lt;b&gt;보드레이트&lt;/b&gt;로 1비트 시간을 미리 약속한다. (1비트 = 1/보드레이트)&lt;/li&gt;
&lt;li&gt;프레임 = 시작비트(LOW) + 데이터 8비트(&lt;b&gt;LSB first&lt;/b&gt;) + (패리티) + 정지비트(HIGH). 흔히 &lt;b&gt;8N1&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;글자 깨지면(&lt;code&gt;?????&lt;/code&gt;) 제일 먼저 &lt;b&gt;양쪽 보드레이트&lt;/b&gt;를 의심하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클럭선 없이 시간 약속만으로 데이터를 주고받는다는 게 처음엔 신기했는데, 프레임 구조를 보고 나니 납득이 됐다. I2C, SPI, UART까지 봤으니 기본적인 통신 3종은 얼추 정리된 느낌이다. 다음엔 통신 말고 &lt;b&gt;ADC(아날로그 값 읽기)&lt;/b&gt;를 정리해봐야겠다.&lt;/p&gt;</description>
      <category>프로그래밍/마이컴</category>
      <category>AVR</category>
      <category>UART</category>
      <category>마이컴</category>
      <category>시리얼</category>
      <category>임베디드</category>
      <category>통신</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/161</guid>
      <comments>https://manggsoft.tistory.com/161#entry161comment</comments>
      <pubDate>Sun, 19 Jul 2026 05:13:33 +0900</pubDate>
    </item>
    <item>
      <title>SPI 통신</title>
      <link>https://manggsoft.tistory.com/160</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저번엔 I2C를 정리했으니 이번엔 SPI를 정리해본다. 둘이 사촌지간 같은 녀석들이라 I2C 알고 나면 SPI는 오히려 쉽다.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;라고 나도 처음엔 그렇게 생각했다 ㅋㅋ&lt;/del&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;용어적 설명부터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPI(Serial Peripheral Interface)는 모토로라에서 개발한 &lt;b&gt;동기식 직렬 통신&lt;/b&gt; 방식이다. 마이크로컨트롤러와 주변 기기(센서, EEPROM, SD카드, LCD 등) 사이에서 짧은 거리 고속 통신에 널리 쓰인다. &quot;에스-피-아이&quot; 라고 그냥 읽으면 된다. 이건 발음 시비 걸릴 게 없어서 마음이 편하다 ^^&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPI는 기본적으로 &lt;b&gt;4개의 라인&lt;/b&gt;을 사용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SCLK (SCK)&lt;/b&gt; : 클럭. 마스터가 만들어서 내보낸다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MOSI&lt;/b&gt; : Master Out Slave In. 마스터 &amp;rarr; 슬레이브 방향 데이터.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MISO&lt;/b&gt; : Master In Slave Out. 슬레이브 &amp;rarr; 마스터 방향 데이터.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SS (CS)&lt;/b&gt; : Slave Select(Chip Select). 마스터가 &quot;너랑 얘기할래&quot; 하고 슬레이브를 지목하는 선. 보통 &lt;b&gt;LOW일 때 선택(active low)&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spi-wiring.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcSFdR/dJMcagM7Fe7/61dO8pwYBWkXU3WSs19ceK/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcSFdR/dJMcagM7Fe7/61dO8pwYBWkXU3WSs19ceK/tfile.svg&quot; data-alt=&quot;SPI 4선 결선도. 클럭은 마스터가 만들고, MOSI/MISO는 마스터 기준 이름이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcSFdR/dJMcagM7Fe7/61dO8pwYBWkXU3WSs19ceK/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcSFdR%2FdJMcagM7Fe7%2F61dO8pwYBWkXU3WSs19ceK%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;360&quot; data-filename=&quot;spi-wiring.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SPI 4선 결선도. 클럭은 마스터가 만들고, MOSI/MISO는 마스터 기준 이름이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 이름 헷갈리지 말자. &lt;b&gt;MOSI, MISO는 마스터 기준&lt;/b&gt;이다. 마스터든 슬레이브든 칩에 적힌 핀 이름은 똑같이 MOSI/MISO라서, &quot;마스터의 MOSI &amp;harr; 슬레이브의 MOSI&quot; 이렇게 그냥 같은 이름끼리 이어주면 된다. (몇몇 칩은 SDI/SDO로 적혀있기도 한데 그건 또 반대로 이어야 해서&amp;hellip; 처음에 여기서 배선 한 번 틀렸다 ㅡㅡ;;;)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래서 I2C랑 뭐가 다른데?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I2C를 먼저 봤으니 비교로 이해하는 게 제일 빠르다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;I2C&lt;/th&gt;
&lt;th&gt;SPI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;선 개수&lt;/th&gt;
&lt;td&gt;2선 (SDA, SCL)&lt;/td&gt;
&lt;td&gt;4선 (SCK, MOSI, MISO, SS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;슬레이브 구분&lt;/th&gt;
&lt;td&gt;주소(7비트)&lt;/td&gt;
&lt;td&gt;SS선을 따로 하나씩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;통신 방향&lt;/th&gt;
&lt;td&gt;반이중 (한 선으로 주고받음)&lt;/td&gt;
&lt;td&gt;전이중 (MOSI/MISO 동시에)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;속도&lt;/th&gt;
&lt;td&gt;100k ~ 3.4Mbit/s&lt;/td&gt;
&lt;td&gt;보통 수~수십 MHz, 더 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;START/STOP, ACK&lt;/th&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;td&gt;없음 (그냥 SS로 시작/끝)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 SPI는 &lt;b&gt;주소 개념이 없다.&lt;/b&gt; 슬레이브가 여러 개면 SS선을 슬레이브 수만큼 따로 뽑아서 &quot;이번엔 너!&quot; 하고 하나만 LOW로 내려주는 방식이다. 그래서 슬레이브가 많아지면 선이 늘어난다는 단점이 있다. 대신 START/STOP이나 ACK 같은 규칙이 없어서 프로토콜 자체는 훨씬 단순하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터 전송은 어떻게?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPI는 START/STOP이 없다. 그럼 언제 시작하고 끝나느냐?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시작&lt;/b&gt; : 마스터가 &lt;b&gt;SS를 LOW로&lt;/b&gt; 내리면 그 슬레이브랑 통신 시작.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;끝&lt;/b&gt; : 다시 &lt;b&gt;SS를 HIGH로&lt;/b&gt; 올리면 끝.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 I2C의 START/STOP 역할을 대신한다. 훨씬 직관적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 마스터가 만드는 &lt;b&gt;클럭(SCK)에 맞춰 한 비트씩&lt;/b&gt; 흘러간다. 핵심은 &lt;b&gt;전이중&lt;/b&gt;이라는 거다. 마스터가 MOSI로 1비트 내보낼 때, &lt;b&gt;동시에&lt;/b&gt; MISO로 슬레이브가 보낸 1비트가 들어온다. 즉 &lt;b&gt;보내기와 받기가 한 번에&lt;/b&gt; 일어난다. (I2C는 쓸 때 쓰고 읽을 때 읽었지만 SPI는 동시다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spi-fullduplex.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk4KzS/dJMcaiKNVL4/YkBLMqkAoKOk0X0c2V5sRk/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk4KzS/dJMcaiKNVL4/YkBLMqkAoKOk0X0c2V5sRk/tfile.svg&quot; data-alt=&quot;SCK 8펄스면 마스터와 슬레이브의 바이트가 통째로 맞교환된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk4KzS/dJMcaiKNVL4/YkBLMqkAoKOk0X0c2V5sRk/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk4KzS%2FdJMcaiKNVL4%2FYkBLMqkAoKOk0X0c2V5sRk%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;340&quot; data-filename=&quot;spi-fullduplex.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SCK 8펄스면 마스터와 슬레이브의 바이트가 통째로 맞교환된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 처음에 나를 괴롭혔던 게 &lt;b&gt;CPOL / CPHA&lt;/b&gt; 라는 놈이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPOL (클럭 극성)&lt;/b&gt; : 통신 안 할 때(idle) SCK가 LOW냐(0) HIGH냐(1).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPHA (클럭 위상)&lt;/b&gt; : 데이터를 클럭의 &lt;b&gt;앞쪽 엣지&lt;/b&gt;에서 읽냐(0) &lt;b&gt;뒷쪽 엣지&lt;/b&gt;에서 읽냐(1).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘 조합으로 &lt;b&gt;모드 0~3&lt;/b&gt;이 나온다. 뭐 복잡해 보이지만, 실무에선 &lt;b&gt;데이터시트에 &quot;이 칩은 SPI 모드 0&quot; 이런 식으로 적혀 있으니&lt;/b&gt; 그거 맞춰주면 된다. 제일 흔한 게 &lt;b&gt;모드 0 (CPOL=0, CPHA=0)&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모드 0 기준: 평소 SCK는 LOW, &lt;b&gt;SCK가 올라가는(상승) 엣지에서 데이터를 읽는다.&lt;/b&gt; MOSI/MISO 값은 SCK가 내려가 있을 때 바꿔놓는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spi-timing-mode0.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8dOms/dJMcaiYjalS/pUMNyZKcyhTEK6qi2dESf1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8dOms/dJMcaiYjalS/pUMNyZKcyhTEK6qi2dESf1/tfile.svg&quot; data-alt=&quot;모드 0: SS를 내리고, SCK 상승 엣지(&amp;amp;uarr;)마다 데이터를 읽는다. (● = 읽는 순간)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8dOms/dJMcaiYjalS/pUMNyZKcyhTEK6qi2dESf1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8dOms%2FdJMcaiYjalS%2FpUMNyZKcyhTEK6qi2dESf1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;420&quot; data-filename=&quot;spi-timing-mode0.svg&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;모드 0: SS를 내리고, SCK 상승 엣지(&amp;uarr;)마다 데이터를 읽는다. (● = 읽는 순간)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로 하면 헷갈리니까 그냥 코드로 보자. (이게 마음이 편하다.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드로 보자 (비트뱅잉, 모드 0 기준)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I2C 때처럼 PORTC 핀을 직접 두드리는 방식이다. 핀 배치는 예시니까 본인 보드에 맞게 바꾸면 된다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#define MOSI        PORTC_Bit4   // 마스터가 내보내는 데이터
#define MISO_IN     PINC_Bit5    // 슬레이브가 보낸 데이터 (입력)
#define SCK         PORTC_Bit6   // 클럭 (마스터가 생성)
#define SS          PORTC_Bit7   // 슬레이브 선택 (active low)

// 슬레이브 선택 : SS를 LOW로
void SPI_Start(void)
{
    DDRC = 0xDC;    // MOSI, SCK, SS = 출력 / MISO = 입력
    SCK = 0;        // 모드 0 : idle 클럭은 LOW
    SS  = 0;        // 슬레이브 선택 시작
    USEC_Delay(1);
}

// 슬레이브 선택 해제 : SS를 HIGH로
void SPI_Stop(void)
{
    SS = 1;         // 통신 끝
    USEC_Delay(1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 핵심인 데이터 주고받기다. SPI는 전이중이라 &lt;b&gt;보내면서 동시에 받는다.&lt;/b&gt; 그래서 함수 하나로 끝난다. &lt;code&gt;val&lt;/code&gt;을 내보내면서, 그 사이에 들어온 값을 리턴한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 1바이트 전송 + 동시에 1바이트 수신 (MSB first, 모드 0)
BYTE SPI_Transfer(BYTE val)
{
    BYTE i;
    BYTE recv = 0;

    for(i = 0x80; i &amp;gt; 0; i /= 2)   // MSB부터 8비트
    {
        // 1) SCK가 LOW인 동안 MOSI에 보낼 비트를 올려둔다
        if (i &amp;amp; val) MOSI = 1;
        else         MOSI = 0;
        USEC_Delay(1);

        // 2) SCK 상승 엣지 : 이 순간 서로 데이터를 읽는다
        SCK = 1;
        if (MISO_IN) recv = (recv | i);   // 들어온 비트를 저장
        USEC_Delay(1);

        // 3) SCK 하강 : 다음 비트 준비
        SCK = 0;
        USEC_Delay(1);
    }

    return recv;   // 나가는 동안 들어온 8비트
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I2C와 비교해보면 재밌다. I2C는 &lt;code&gt;I2CWrite_Data()&lt;/code&gt;, &lt;code&gt;I2CRead_Data()&lt;/code&gt;가 따로 있었는데, SPI는 &lt;code&gt;SPI_Transfer()&lt;/code&gt; 하나가 쓰기/읽기를 겸한다. &lt;b&gt;&quot;보내는 만큼 받는다&quot;&lt;/b&gt;가 SPI의 성격이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;쓰기만 하고 싶다&lt;/b&gt; &amp;rarr; 리턴값 무시하면 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;읽기만 하고 싶다&lt;/b&gt; &amp;rarr; 아무 값(보통 0x00, 더미 바이트)이나 보내면서 리턴값을 받으면 된다. 어차피 클럭을 굴려야 슬레이브가 데이터를 실어주니까.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;전체 흐름 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 SPI EEPROM에서 데이터를 하나 읽는다고 해보자. (명령 &amp;rarr; 주소 &amp;rarr; 더미 보내며 읽기)&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void main(void)
{
    BYTE data;

    SPI_Start();              // SS LOW : 슬레이브 선택

    SPI_Transfer(0x03);       // READ 명령 (예시)
    SPI_Transfer(0x00);       // 읽을 주소 상위
    SPI_Transfer(0x10);       // 읽을 주소 하위

    data = SPI_Transfer(0x00); // 더미(0x00) 보내면서 실제 데이터 수신

    SPI_Stop();               // SS HIGH : 선택 해제
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인트는 &lt;b&gt;마지막 &lt;code&gt;SPI_Transfer(0x00)&lt;/code&gt;&lt;/b&gt;이다. 보낼 데이터는 없지만 &lt;b&gt;클럭을 굴려야 슬레이브가 MISO로 값을 실어주기 때문에&lt;/b&gt; 더미 바이트를 하나 흘려보내는 거다. 이게 처음엔 &quot;왜 굳이 0을 보내?&quot; 싶었는데, 전이중이라 클럭이 있어야만 데이터가 나온다는 걸 생각하면 납득이 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리하면&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SPI = 4선(SCK, MOSI, MISO, SS), 마스터가 클럭을 만든다.&lt;/li&gt;
&lt;li&gt;슬레이브 구분은 주소가 아니라 &lt;b&gt;SS선&lt;/b&gt;. LOW로 내리면 선택, HIGH로 올리면 끝.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전이중&lt;/b&gt; &amp;mdash; 보내면서 동시에 받는다. 그래서 함수 하나(&lt;code&gt;SPI_Transfer&lt;/code&gt;)로 끝.&lt;/li&gt;
&lt;li&gt;CPOL/CPHA(모드)는 데이터시트 보고 맞춰주면 된다. 흔한 건 모드 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I2C보다 선은 많지만 프로토콜은 오히려 단순하다. START/STOP/ACK 같은 거 신경 안 쓰고 SS만 잘 내렸다 올리면 되니까. 다음엔 SPI 모드(CPOL/CPHA) 4개를 파형으로 하나씩 뜯어보든가 해야겠다.&lt;/p&gt;</description>
      <category>프로그래밍/마이컴</category>
      <category>#SPI #통신 #임베디드 #마이컴 #AVR</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/160</guid>
      <comments>https://manggsoft.tistory.com/160#entry160comment</comments>
      <pubDate>Sun, 19 Jul 2026 04:35:58 +0900</pubDate>
    </item>
    <item>
      <title>[ENG] How to Install CloudZIP on Mac</title>
      <link>https://manggsoft.tistory.com/159</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;CloudZip &amp;mdash; Download &amp;amp; Installation Guide&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A quick guide for first-time users. On the Mac, an app downloaded from outside the App Store may show a security prompt the first time you open it. Follow the steps below and it will run without any issue.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Download&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Get the latest version (&lt;b&gt;1.0.0&lt;/b&gt;) from the link below.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  [&lt;a href=&quot;https://cloudzip.manggong.org/CloudZip-1.0.0.dmg&quot;&gt;download link &amp;mdash; CloudZip-1.0.0.dmg&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;macOS 13 Ventura or later&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Universal binary&lt;/b&gt; &amp;mdash; runs natively on both Apple silicon (M1 and later) and Intel Macs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Install&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Double-click the downloaded &lt;b&gt;.dmg&lt;/b&gt;, then &lt;b&gt;drag the CloudZip icon into your &lt;code&gt;Applications&lt;/code&gt; folder&lt;/b&gt;. That's it.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;08_drag_install.png&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BqOHp/dJMcaixmgOA/rnsyoG2UNihvPWhJzZWYVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BqOHp/dJMcaixmgOA/rnsyoG2UNihvPWhJzZWYVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BqOHp/dJMcaixmgOA/rnsyoG2UNihvPWhJzZWYVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBqOHp%2FdJMcaixmgOA%2FrnsyoG2UNihvPWhJzZWYVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;476&quot; height=&quot;300&quot; data-filename=&quot;08_drag_install.png&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;736&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. First Launch (clearing the security prompt)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudZip is distributed by an independent developer, so the first launch may show &lt;i&gt;&quot;unidentified developer&quot;&lt;/i&gt; or &lt;i&gt;&quot;cannot be opened.&quot;&lt;/i&gt; This is expected &amp;mdash; allow it once and it opens normally afterward.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ Option 1 &amp;mdash; Open via right-click (macOS 14 and earlier)&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;In &lt;code&gt;Applications&lt;/code&gt;, &lt;b&gt;right-click (or Control-click) the CloudZip icon&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Choose &lt;b&gt;Open&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;b&gt;Open&lt;/b&gt; again in the dialog&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ Option 2 &amp;mdash; Allow in System Settings (macOS 15 Sequoia or later)&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Try launching CloudZip once (the prompt appears and closes)&lt;/li&gt;
&lt;li&gt;Open &lt;b&gt;System Settings &amp;rarr; Privacy &amp;amp; Security&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Scroll down and click &lt;b&gt;Open Anyway&lt;/b&gt; next to the &quot;CloudZip was blocked&quot; notice&lt;/li&gt;
&lt;li&gt;Confirm with &lt;b&gt;Open&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ Option 3 &amp;mdash; If it says &quot;damaged and can't be opened&quot; (Terminal)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rarely you may see &lt;i&gt;&quot;CloudZip is damaged and can't be opened.&quot;&lt;/i&gt; This is due to the download quarantine attribute. Open &lt;b&gt;Terminal&lt;/b&gt; (Applications &amp;rarr; Utilities &amp;rarr; Terminal), paste the command, and press&lt;/p&gt;
&lt;p&gt;&lt;kbd&gt;Enter&lt;/kbd&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;xattr -dr com.apple.quarantine /Applications/CloudZip.app&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Then launch it again &amp;mdash; it will open normally.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Enable the Finder Right-Click Menu&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;To use &lt;b&gt;right-click &amp;rarr; Compress / Extract&lt;/b&gt; in Finder, enable the extension once.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Launch CloudZip once&lt;/li&gt;
&lt;li&gt;Open &lt;b&gt;System Settings &amp;rarr; General &amp;rarr; Login Items &amp;amp; Extensions&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Under &lt;b&gt;Finder extensions&lt;/b&gt;, turn on &lt;b&gt;CloudZip&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Right-clicking files or folders now shows &lt;b&gt;Extract Here / Extract to &quot;&amp;hellip;&quot; / Compress with CloudZip&lt;/b&gt;.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. (Optional) Install the 'cloudzip' Terminal Command&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;To compress/extract from the terminal or scripts:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Launch CloudZip&lt;/li&gt;
&lt;li&gt;Choose &lt;b&gt;CloudZip &amp;rarr; Install Command Line Tool&amp;hellip;&lt;/b&gt; from the menu (enter your admin password once)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;This creates a &lt;code&gt;/usr/local/bin/cloudzip&lt;/code&gt; link so you can use it right away:&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;cloudzip -h                    # help
cloudzip l file.zip            # list
cloudzip x file.zip -o ./out   # extract
cloudzip c backup.zip folder -l 9   # compress&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Updating&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;When a new version is out, download it the same way and replace the existing CloudZip in your &lt;code&gt;Applications&lt;/code&gt; folder. (Quit the app first if it's running.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CloudZIP</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/159</guid>
      <comments>https://manggsoft.tistory.com/159#entry159comment</comments>
      <pubDate>Sun, 19 Jul 2026 03:37:03 +0900</pubDate>
    </item>
    <item>
      <title>[ENG] CloudZIP 1.0.0 - Zip,Unzip &amp;amp; Extract Archives on Mac</title>
      <link>https://manggsoft.tistory.com/158</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;CloudZip &amp;mdash; A Lightweight, Native Archive Manager for Mac&lt;/h2&gt;
&lt;p style=&quot;display: inline-block; background: #eef4ff; border: 1px solid #cfe0ff; border-radius: 8px; padding: 10px 16px; font-size: 14px; color: #1a3b6e; margin: 6px 0 18px; line-height: 1.6;&quot; data-ke-size=&quot;size16&quot;&gt;⚙️ &lt;b&gt;Requirements&lt;/b&gt; &amp;mdash; macOS 13 Ventura or later &amp;middot; Universal (Apple silicon &amp;amp; Intel)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Handling archives on the Mac has always been a bit frustrating. The built-in tools garble non-Latin filenames, struggle with anything beyond ZIP, and offer almost no options. So I built an archive manager that is &lt;b&gt;intuitive and designed for the Mac&lt;/b&gt;. It's called &lt;b&gt;CloudZip&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_main.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9Apch/dJMcadCEyzB/QhTVg4KMCDmDrWESWMV3k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9Apch/dJMcadCEyzB/QhTVg4KMCDmDrWESWMV3k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9Apch/dJMcadCEyzB/QhTVg4KMCDmDrWESWMV3k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9Apch%2FdJMcadCEyzB%2FQhTVg4KMCDmDrWESWMV3k1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;400&quot; data-filename=&quot;01_main.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ㅁ Supported Formats&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Extract (open)&lt;/b&gt; &amp;mdash; virtually every major format is supported.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Common&lt;/b&gt;: ZIP, ZIPX, 7Z, RAR, TAR, GZ (TGZ), BZ2 (TBZ), XZ (TXZ), LZ, LZMA, Z, ZST&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Disk &amp;amp; installer&lt;/b&gt;: ISO, IMG, CAB, WIM, XAR, CPIO&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Others&lt;/b&gt;: LHA/LZH, ARJ, SIT/SITX&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Compress (create)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ZIP, 7Z, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, TAR.ZST&lt;/li&gt;
&lt;li&gt;ZIP also supports &lt;b&gt;password protection (encrypted ZIP)&lt;/b&gt; and &lt;b&gt;split archives&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ㅁ Key Features&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Fast, Powerful Compression&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Multi-core parallel compression&lt;/b&gt; for high speed&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fast archiving&lt;/b&gt; &amp;mdash; already-compressed files (photos, videos, PDFs, etc.) are stored without re-compression, saving significant time&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Password (encrypted ZIP)&lt;/b&gt; and &lt;b&gt;split archives&lt;/b&gt; (10MB / 100MB / 700MB / 1GB / 4GB)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;03_compress.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;974&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCcOo0/dJMcagTPONb/qYBDikrJvVHEUXep94a2Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCcOo0/dJMcagTPONb/qYBDikrJvVHEUXep94a2Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCcOo0/dJMcagTPONb/qYBDikrJvVHEUXep94a2Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCcOo0%2FdJMcagTPONb%2FqYBDikrJvVHEUXep94a2Z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;366&quot; height=&quot;300&quot; data-filename=&quot;03_compress.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;974&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Edit ZIP Without Extracting&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;No need to fully unpack and repack &amp;mdash; edit directly inside a ZIP.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Add&lt;/b&gt; files and folders (drag &amp;amp; drop onto the list)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Delete&lt;/b&gt; (Delete key / right-click)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rename&lt;/b&gt; and create a &lt;b&gt;new folder&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Move&lt;/b&gt; items into another folder (drag onto the folder tree on the left)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Existing compressed data is left untouched and only the changes are written, so it's &lt;b&gt;extremely fast.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_edit_zip.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q6ITF/dJMcafHqHhh/aB3DykMZVJmMeWYJatQ820/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q6ITF/dJMcafHqHhh/aB3DykMZVJmMeWYJatQ820/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q6ITF/dJMcafHqHhh/aB3DykMZVJmMeWYJatQ820/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq6ITF%2FdJMcafHqHhh%2FaB3DykMZVJmMeWYJatQ820%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;300&quot; data-filename=&quot;02_edit_zip.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;No More Garbled Filenames&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Legacy filename encodings (CP949, Shift-JIS, GBK) are automatically detected, so CJK filenames display and extract &lt;b&gt;without corruption.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Deep Finder Integration&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Right-click &amp;rarr; Compress / Extract&lt;/b&gt; right in Finder&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Drag files out&lt;/b&gt; of an archive straight into Finder to extract them&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Double-click&lt;/b&gt; an archive to open it in CloudZip&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_finder_menu.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/11CWT/dJMcacDW2yv/l38WKjp5ubFJn88gA0Vr10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/11CWT/dJMcacDW2yv/l38WKjp5ubFJn88gA0Vr10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/11CWT/dJMcacDW2yv/l38WKjp5ubFJn88gA0Vr10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F11CWT%2FdJMcacDW2yv%2Fl38WKjp5ubFJn88gA0Vr10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;300&quot; data-filename=&quot;06_finder_menu.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Quick Look Preview&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Preview photos, documents, and more &lt;b&gt;without extracting&lt;/b&gt; the archive.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;07_quicklook.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPdvm0/dJMcafHqHhj/vOMdk3e1LzcGFLIX7FSqa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPdvm0/dJMcafHqHhj/vOMdk3e1LzcGFLIX7FSqa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPdvm0/dJMcafHqHhj/vOMdk3e1LzcGFLIX7FSqa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPdvm0%2FdJMcafHqHhj%2FvOMdk3e1LzcGFLIX7FSqa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;386&quot; height=&quot;300&quot; data-filename=&quot;07_quicklook.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Simple Drag &amp;amp; Drop&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Just drag files and folders onto the window to queue them, then hit &lt;b&gt;Compress&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;04_drag_to_compress.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bltdIy/dJMcajpmkRW/pHhKinjiwHfbMhon7Kku1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bltdIy/dJMcajpmkRW/pHhKinjiwHfbMhon7Kku1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bltdIy/dJMcajpmkRW/pHhKinjiwHfbMhon7Kku1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbltdIy%2FdJMcajpmkRW%2FpHhKinjiwHfbMhon7Kku1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;300&quot; data-filename=&quot;04_drag_to_compress.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Fine-Grained Preferences&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set your default format, compression level, filename encoding, fast archiving, and file associations. Available in &lt;b&gt;5 languages&lt;/b&gt;: English, Korean, Japanese, Chinese (Simplified/Traditional).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_preferences.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;991&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdCL1D/dJMcafHqHhH/zdUIOF4vzn5cgaJliW1PnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdCL1D/dJMcafHqHhH/zdUIOF4vzn5cgaJliW1PnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdCL1D/dJMcafHqHhH/zdUIOF4vzn5cgaJliW1PnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdCL1D%2FdJMcafHqHhH%2FzdUIOF4vzn5cgaJliW1PnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;360&quot; height=&quot;300&quot; data-filename=&quot;05_preferences.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;991&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Command-Line Tool&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Beyond the GUI, the &lt;b&gt;&lt;code&gt;cloudzip&lt;/code&gt; terminal command&lt;/b&gt; can compress, extract, and list archives &amp;mdash; great for scripts and automation.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;cloudzip l archive.zip                   # list
cloudzip x archive.7z -o ./out           # extract
cloudzip c backup.tar.zst docs photos -l 9   # compress&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enable it once from the app menu: &lt;b&gt;CloudZip &amp;rarr; Install Command Line Tool&amp;hellip;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ㅁ &amp;nbsp;System Requirements&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;macOS 13 Ventura or later&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Universal binary&lt;/b&gt; &amp;mdash; runs natively on both Apple silicon (M1 and later) and Intel Macs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ㅁ &amp;nbsp;Download &amp;amp; Install&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;On first launch macOS may show a security prompt. See the &lt;b&gt;[&lt;a href=&quot;https://manggong.org/159&quot;&gt;install guide link&lt;/a&gt;]&lt;/b&gt; for step-by-step instructions.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[&lt;a href=&quot;https://cloudzip.manggong.org/CloudZip-1.0.0.dmg&quot;&gt;Download Link&lt;/a&gt;]&lt;/p&gt;</description>
      <category>CloudZIP</category>
      <category>7z</category>
      <category>archive manager</category>
      <category>CloudZip</category>
      <category>Compression</category>
      <category>free Mac app</category>
      <category>Mac</category>
      <category>mac app</category>
      <category>MacOS</category>
      <category>unzip</category>
      <category>Zip</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/158</guid>
      <comments>https://manggsoft.tistory.com/158#entry158comment</comments>
      <pubDate>Sun, 19 Jul 2026 03:28:15 +0900</pubDate>
    </item>
    <item>
      <title>구름집 설치 가이드</title>
      <link>https://manggsoft.tistory.com/157</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;구름집(CloudZip) 다운로드 &amp;amp; 설치 가이드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름집을 처음 설치하는 분들을 위한 안내입니다. 맥에서는 외부에서 받은 앱을 처음 열 때 보안 경고가 뜰 수 있는데, 아래 순서대로 하면 문제없이 실행됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 다운로드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크에서 최신 버전(&lt;b&gt;1.0.0&lt;/b&gt;)을 내려받으세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;[&lt;a href=&quot;https://cloudzip.manggong.org/CloudZip-1.0.0.dmg&quot;&gt;다운로드 링크 &amp;mdash; CloudZip-1.0.0.dmg&lt;/a&gt;]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;macOS 13 Ventura 이상&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Apple 실리콘(M1~)&amp;middot;인텔 맥 모두 지원&lt;/b&gt; (유니버설 바이너리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내려받은 &lt;b&gt;.dmg&lt;/b&gt; 파일을 두 번 눌러 열고, 나타나는 &lt;b&gt;구름집 아이콘을 &lt;code&gt;응용 프로그램&lt;/code&gt;(Applications) 폴더로 끌어다 놓으면&lt;/b&gt; 설치가 끝납니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;08_드래그설치.png&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brg0QX/dJMcaaTAJnG/FKMkuaykNgQKpjyhdUDLG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brg0QX/dJMcaaTAJnG/FKMkuaykNgQKpjyhdUDLG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brg0QX/dJMcaaTAJnG/FKMkuaykNgQKpjyhdUDLG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbrg0QX%2FdJMcaaTAJnG%2FFKMkuaykNgQKpjyhdUDLG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;270&quot; height=&quot;170&quot; data-filename=&quot;08_드래그설치.png&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;736&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 처음 실행하기 (보안 경고 해제)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름집은 개인 개발자가 배포하는 앱이라, 처음 열 때 &lt;i&gt;&quot;확인되지 않은 개발자&quot;&lt;/i&gt; 또는 &lt;i&gt;&quot;열 수 없습니다&quot;&lt;/i&gt; 경고가 뜰 수 있습니다. 정상이며, 아래 방법으로 한 번만 허용하면 이후로는 그냥 열립니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 방법 1 &amp;mdash; 우클릭으로 열기 (macOS 14 이하)&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;응용 프로그램&lt;/code&gt; 폴더에서 &lt;b&gt;구름집 아이콘을 우클릭(또는 Control+클릭)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;메뉴에서 &lt;b&gt;[열기]&lt;/b&gt; 선택&lt;/li&gt;
&lt;li&gt;경고창에서 다시 &lt;b&gt;[열기]&lt;/b&gt; 클릭&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 방법 2 &amp;mdash; 시스템 설정에서 허용 (macOS 15 Sequoia 이상)&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;구름집을 한 번 실행 시도 (경고가 뜨고 닫힘)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 설정 &amp;rarr; 개인정보 보호 및 보안&lt;/b&gt; 열기&lt;/li&gt;
&lt;li&gt;아래로 스크롤 &amp;rarr; &lt;i&gt;&quot;구름집이(가) 차단되었습니다&quot;&lt;/i&gt; 안내의 &lt;b&gt;[그래도 열기]&lt;/b&gt; 클릭&lt;/li&gt;
&lt;li&gt;다시 뜨는 확인창에서 &lt;b&gt;[열기]&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 방법 3 &amp;mdash; &quot;손상되어 열 수 없습니다&quot;가 뜰 때 (터미널)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드물게 &lt;i&gt;&quot;손상되었기 때문에 열 수 없습니다&quot;&lt;/i&gt; 메시지가 나오면 다운로드 격리 속성 때문입니다. &lt;b&gt;터미널&lt;/b&gt;(응용 프로그램 &amp;rarr; 유틸리티 &amp;rarr; 터미널)에서 아래를 붙여넣고&lt;/p&gt;
&lt;p&gt;&lt;kbd&gt;Enter&lt;/kbd&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;xattr -dr com.apple.quarantine /Applications/CloudZip.app&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 다음 다시 실행하면 정상적으로 열립니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 파인더 우클릭 메뉴 켜기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파인더에서 &lt;b&gt;우클릭 &amp;rarr; 압축 / 압축 풀기&lt;/b&gt;를 쓰려면 확장 기능을 한 번 켜줘야 합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;구름집을 한 번 실행합니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 설정 &amp;rarr; 일반 &amp;rarr; 로그인 항목 및 확장 프로그램&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Finder 확장 프로그램&lt;/b&gt;에서 &lt;b&gt;구름집&lt;/b&gt;을 켭니다(체크)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 파일&amp;middot;폴더를 우클릭하면 &lt;b&gt;여기에 압축 풀기 / &amp;lsquo;파일명&amp;rsquo; 폴더에 압축 풀기 / CloudZip으로 압축하기&lt;/b&gt; 메뉴가 나타납니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. (선택) 터미널 명령 'cloudzip' 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널&amp;middot;스크립트에서 압축&amp;middot;풀기를 하고 싶다면:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;구름집을 실행합니다&lt;/li&gt;
&lt;li&gt;메뉴 &lt;b&gt;구름집 &amp;rarr; 명령줄 도구 설치&amp;hellip;&lt;/b&gt; 클릭 (관리자 암호 1회)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 &lt;code&gt;/usr/local/bin/cloudzip&lt;/code&gt; 링크가 생기고, 터미널에서 바로 쓸 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;cloudzip -h                  # 도움말
cloudzip l 파일.zip           # 목록
cloudzip x 파일.zip -o ./out  # 풀기
cloudzip c 백업.zip 폴더 -l 9  # 압축&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 업데이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새 버전이 나오면 같은 방법으로 내려받아 &lt;code&gt;응용 프로그램&lt;/code&gt; 폴더의 기존 구름집을 덮어쓰면 됩니다. (실행 중이면 먼저 종료해 주세요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 중 막히는 부분이 있으면 댓글로 남겨주세요.&amp;nbsp;&lt;/p&gt;</description>
      <category>CloudZIP</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/157</guid>
      <comments>https://manggsoft.tistory.com/157#entry157comment</comments>
      <pubDate>Sun, 19 Jul 2026 02:57:13 +0900</pubDate>
    </item>
    <item>
      <title>구름집 1.0.0 배포 - 맥용 무료 압축 프로그램</title>
      <link>https://manggsoft.tistory.com/156</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;구름집(CloudZip) &amp;mdash; 가볍고 편한 맥용 압축 프로그램&lt;/h2&gt;
&lt;p style=&quot;display: inline-block; background: #eef4ff; border: 1px solid #cfe0ff; border-radius: 8px; padding: 10px 16px; font-size: 14px; color: #1a3b6e; margin: 6px 0 18px; line-height: 1.6;&quot; data-ke-size=&quot;size16&quot;&gt;⚙️ &lt;b&gt;요구 사양&lt;/b&gt; &amp;mdash; macOS 13 Ventura 이상 &amp;middot; Apple 실리콘(M1~)/인텔 맥 모두 지원 (유니버설 바이너리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥에서 압축 파일을 다루다 보면 늘 아쉬웠습니다. 기본 압축 유틸리티는 한글 파일명이 깨지고, ZIP 말고는 제대로 못 열고, 세밀한 옵션도 없죠. 그래서 &lt;b&gt;직관적이면서 맥에 딱 맞는&lt;/b&gt; 압축 관리자를 직접 만들었습니다. 이름은 &lt;b&gt;구름집&lt;/b&gt;입니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;01_메인화면.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciwyhP/dJMcabrryct/YYtDsKqdZ51zZK7nb4GGCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciwyhP/dJMcabrryct/YYtDsKqdZ51zZK7nb4GGCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciwyhP/dJMcabrryct/YYtDsKqdZ51zZK7nb4GGCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciwyhP%2FdJMcabrryct%2FYYtDsKqdZ51zZK7nb4GGCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;400&quot; data-filename=&quot;01_메인화면.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;br /&gt;ㅁ 지원 형식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;압축 풀기(열기)&lt;/b&gt; &amp;mdash; 사실상 모든 주요 형식을 지원합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;일반&lt;/b&gt;: ZIP, ZIPX, 7Z, RAR, TAR, GZ(TGZ), BZ2(TBZ), XZ(TXZ), LZ, LZMA, Z, ZST&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스크&amp;middot;설치&lt;/b&gt;: ISO, IMG, CAB, WIM, XAR, CPIO&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기타&amp;middot;국내&lt;/b&gt;: LHA/LZH, ARJ, SIT/SITX &amp;mdash; 그리고 국내에서 많이 쓰는 &lt;b&gt;EGG&amp;middot;ALZ&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;압축(만들기)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ZIP, 7Z, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, TAR.ZST&lt;/li&gt;
&lt;li&gt;ZIP은 &lt;b&gt;암호 설정(암호화 ZIP)&lt;/b&gt;과 &lt;b&gt;분할 압축&lt;/b&gt;도 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;br /&gt;ㅁ 주요 기능&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;빠르고 강력한 압축&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;멀티코어 병렬 압축&lt;/b&gt;으로 빠른 속도&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고속 압축&lt;/b&gt; &amp;mdash; 이미 압축된 파일(사진&amp;middot;영상&amp;middot;PDF 등)은 다시 압축하지 않고 담아 시간을 크게 절약&lt;/li&gt;
&lt;li&gt;&lt;b&gt;암호(암호화 ZIP)&lt;/b&gt;와 &lt;b&gt;분할 압축&lt;/b&gt;(10MB&amp;middot;100MB&amp;middot;700MB&amp;middot;1GB&amp;middot;4GB) 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;03_압축설정.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;976&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qo2sF/dJMcadW5kit/0auzk6pfFakS7yNX4R9WD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qo2sF/dJMcadW5kit/0auzk6pfFakS7yNX4R9WD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qo2sF/dJMcadW5kit/0auzk6pfFakS7yNX4R9WD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQo2sF%2FdJMcadW5kit%2F0auzk6pfFakS7yNX4R9WD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;365&quot; height=&quot;300&quot; data-filename=&quot;03_압축설정.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;976&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;압축 해제 없이 ZIP 수정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;압축을 통째로 풀었다 다시 압축할 필요 없이, ZIP 안에서 바로 편집합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일&amp;middot;폴더 &lt;b&gt;추가&lt;/b&gt; (목록에 드래그&amp;amp;드롭)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제&lt;/b&gt; (Delete 키 / 우클릭)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이름 바꾸기&lt;/b&gt;, &lt;b&gt;새 폴더&lt;/b&gt; 만들기&lt;/li&gt;
&lt;li&gt;파일을 &lt;b&gt;다른 폴더로 이동&lt;/b&gt; (왼쪽 폴더 트리로 끌어다 놓기)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 압축 데이터를 그대로 두고 바뀐 부분만 처리하기 때문에 &lt;b&gt;매우 빠릅니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;02_압축해제없이수정.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IACkS/dJMcabSs2WO/VMJnxoBE2toMrzk2vU2OKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IACkS/dJMcabSs2WO/VMJnxoBE2toMrzk2vU2OKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IACkS/dJMcabSs2WO/VMJnxoBE2toMrzk2vU2OKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIACkS%2FdJMcabSs2WO%2FVMJnxoBE2toMrzk2vU2OKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;300&quot; data-filename=&quot;02_압축해제없이수정.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;한글 파일명 안 깨짐&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구형 압축 파일의 CP949(EUC-KR) 한글 이름은 물론 일본어&amp;middot;중국어 인코딩까지 자동으로 인식해 &lt;b&gt;깨짐 없이&lt;/b&gt; 보여주고 풀어줍니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Finder(파인더)와 완벽 통합&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파인더에서 &lt;b&gt;우클릭 &amp;rarr; 압축 / 압축 풀기&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;압축 파일 안의 파일을 &lt;b&gt;파인더로 바로 끌어내&lt;/b&gt; 꺼내기&lt;/li&gt;
&lt;li&gt;파일을 &lt;b&gt;더블클릭&lt;/b&gt;하면 구름집으로 열기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;06_Finder우클릭.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwK5bY/dJMcaiRDMEG/JzgtpNM58IvknGGA7GEjm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwK5bY/dJMcaiRDMEG/JzgtpNM58IvknGGA7GEjm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwK5bY/dJMcaiRDMEG/JzgtpNM58IvknGGA7GEjm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwK5bY%2FdJMcaiRDMEG%2FJzgtpNM58IvknGGA7GEjm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;300&quot; data-filename=&quot;06_Finder우클릭.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;br /&gt;미리보기 (Quick Look)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;압축을 풀지 않고도 사진&amp;middot;문서 등 파일 내용을 &lt;b&gt;바로 미리보기&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;07_미리보기.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSqMio/dJMcag7jChu/wYK2JUbrCHt4kFs2PGRq5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSqMio/dJMcag7jChu/wYK2JUbrCHt4kFs2PGRq5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSqMio/dJMcag7jChu/wYK2JUbrCHt4kFs2PGRq5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSqMio%2FdJMcag7jChu%2FwYK2JUbrCHt4kFs2PGRq5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;386&quot; height=&quot;300&quot; data-filename=&quot;07_미리보기.png&quot; data-origin-width=&quot;1508&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;br /&gt;드래그 &amp;amp; 드롭으로 간편하게&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일&amp;middot;폴더를 창에 끌어다 놓기만 하면 압축 대기 목록에 담기고, &lt;b&gt;[압축]&lt;/b&gt; 버튼으로 바로 압축됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;04_드래그압축.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZNt3b/dJMcaiD60yF/kbY2EDMhB7G33D0GQ3uG81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZNt3b/dJMcaiD60yF/kbY2EDMhB7G33D0GQ3uG81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZNt3b/dJMcaiD60yF/kbY2EDMhB7G33D0GQ3uG81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZNt3b%2FdJMcaiD60yF%2FkbY2EDMhB7G33D0GQ3uG81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;472&quot; height=&quot;299&quot; data-filename=&quot;04_드래그압축.png&quot; data-origin-width=&quot;2068&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세밀한 환경설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 압축 형식&amp;middot;압축률&amp;middot;파일명 인코딩, 고속 압축, 파일 연결까지 원하는 대로 설정할 수 있습니다. 그리고 &lt;b&gt;한국어&amp;middot;영어&amp;middot;일본어&amp;middot;중국어(간체/번체)&lt;/b&gt; 5개 언어를 지원합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;05_환경설정.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/weiMj/dJMcab52Pqz/3XBd1DpAXN1CI9YPk7V2SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/weiMj/dJMcab52Pqz/3XBd1DpAXN1CI9YPk7V2SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/weiMj/dJMcab52Pqz/3XBd1DpAXN1CI9YPk7V2SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FweiMj%2FdJMcab52Pqz%2F3XBd1DpAXN1CI9YPk7V2SK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;372&quot; height=&quot;301&quot; data-filename=&quot;05_환경설정.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;명령줄(터미널)에서도 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI뿐 아니라 &lt;b&gt;터미널 명령 &lt;code&gt;cloudzip&lt;/code&gt;&lt;/b&gt;으로도 압축&amp;middot;풀기&amp;middot;목록을 처리할 수 있어 스크립트&amp;middot;자동화에 활용하기 좋습니다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;cloudzip l archive.zip                    # 목록
cloudzip x archive.7z -o ./out            # 풀기
cloudzip c backup.tar.zst 문서 사진 -l 9   # 압축&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 메뉴 &lt;b&gt;구름집 &amp;rarr; 명령줄 도구 설치&amp;hellip;&lt;/b&gt;를 한 번 누르면 활성화됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;ㅁ 지원 환경&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;macOS 13 Ventura 이상&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Apple 실리콘(M1~)&amp;middot;인텔 맥 모두 지원&lt;/b&gt; (유니버설 바이너리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;ㅁ 다운로드 &amp;amp; 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 실행할 때 보안 경고가 뜰 수 있습니다. 자세한 설치 방법은 &lt;b&gt;[&lt;a href=&quot;https://manggong.org/157&quot;&gt;설치 가이드 글 링크&lt;/a&gt;]&lt;/b&gt;를 참고하세요.&lt;br /&gt;&lt;br /&gt;[&lt;a href=&quot;https://cloudzip.manggong.org/CloudZip-1.0.0.dmg&quot;&gt;다운로드 &amp;nbsp;- 클릭&lt;/a&gt;]&lt;/p&gt;</description>
      <category>CloudZIP</category>
      <category>7z 압축</category>
      <category>CloudZip</category>
      <category>구름집</category>
      <category>맥 zip</category>
      <category>맥 압축</category>
      <category>맥 압축 풀기</category>
      <category>맥 압축 프로그램</category>
      <category>맥용 프로그램</category>
      <category>무료 압축 프로그램</category>
      <category>압축 프로그램</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/156</guid>
      <comments>https://manggsoft.tistory.com/156#entry156comment</comments>
      <pubDate>Sun, 19 Jul 2026 01:53:21 +0900</pubDate>
    </item>
    <item>
      <title>아이폰 iOS 17.X 메시지앱 먹통</title>
      <link>https://manggsoft.tistory.com/155</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어느날 메시지앱을 켰더니 먹통이 되더니 아무것도 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이폰-&amp;gt; 설정 -&amp;gt; 메시지 를 클릭해도 얼음땡&lt;br /&gt;아이폰-&amp;gt; 설정 -&amp;gt; FaceTime을 클릭해도 얼음땡&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이폰을 몇번을 꼈다 켜도 안되더라..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나, 아이클라우드에 메시지 백업 해 놓은 기능 때문에 그런건지 싶어서&lt;br /&gt;아이클라우드 백업 기능도 모두 끄기 또는 비활성 했는데도 여전히 먹통&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apple ID 로그아웃 을 했더니 되더라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;씨발 애플아, 제대로좀 만들어라..&lt;br /&gt;&lt;br /&gt;3시간동안 삽질 했다...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>소소한 재미</category>
      <author>얼땅불땅</author>
      <guid isPermaLink="true">https://manggsoft.tistory.com/155</guid>
      <comments>https://manggsoft.tistory.com/155#entry155comment</comments>
      <pubDate>Sun, 30 Jun 2024 22:07:50 +0900</pubDate>
    </item>
  </channel>
</rss>