The parameters, in order
The form is ^BCo,h,f,g,e,m. In ^BCN,120,Y,N,N that reads: no rotation, 120 dots tall, print the human-readable line, do not put it above the code, and no check digit.
As with every ZPL command, position is what matters rather than a name: leaving an empty slot between two commas keeps that parameter's default. The barcode's content comes in the ^FD that follows, not here.
- o — orientation: N normal, R 90°, I 180°, B 270°.
- h — bar height in dots. Does not include the human-readable line.
- f — print the human-readable line of digits (Y or N).
- g — put the human-readable line above the code instead of below.
- e — include the UCC check digit (rare on a shipping label).
- m — mode (N, U, A, D). D is the one that enables automatic subset mode.
The width comes from ^BY, not from ^BC
^BC sets the height but not the width. What controls how wide the bars are is ^BY, which applies to every barcode after it: ^BY3 gives a 3-dot module, so each narrow bar becomes 3 dots wide.
That is why a barcode “suddenly stopped fitting”: somebody changed the ^BY at the top and every bar on the label scaled with it. A module too narrow for the printer's resolution does the opposite — the bars merge and the scanner can no longer tell them apart.
When the payload is all digits
Code 128 has subsets, and an all-numeric payload can be encoded in subset C, which packs two digits per symbol and comes out half as wide. That is efficient, but not every downstream system expects it.
Carriers control this by writing the subset at the start of the ^FD: ^FD>:1234567890 starts in subset B and prevents the collapse to C. If your barcode came out half the width you expected, this is what happened.